资讯专栏INFORMATION COLUMN

怎样使用this

cppowboy / 2027人阅读

摘要:构造器的调用这其实很简单,就是使用创建的是一个对象,而不是一个函数这里的指向的就是上的。但需要注意在构造器内不能显示的返回一个对象否则你的实例化就会被破坏。

this的使用

关于js里面有哪些难点,艹,js里面全是难点。。。什么闭包,原型,函数,对象,类型检测,this。。。但是作为一名正统的前端爱好者而言---这点痛算什么。今天我们来解决this这个点。由于牵扯到this,则必定会牵扯到函数,因为没有函数就没有this的存在的意思。
话不多说,Cut~

this的用法通常可以分为:
1. 作为对象的方法调用
2. 作为普通函数调用
3. 构造器调用
4. call,apply调用
作为对象方法调用
var obj = {
    name :"jimmy",
    getName(){
        return this.name;
    }
}
console.log(obj.getName());  // jimmy

这里的this指向的是该对象.由于函数里面this是在运行时指定的,所以有一个诀窍就是,函数里面的this,指的是使用"."调用函数的所有者。

document.querySelector("#jimmy").onclick = function(){
    console.log(this.tagName);  
}

上面的this指的就是document.querySelector("#jimmy")。还有一种情况,当你使用的时候前面什么都没加,则这是函数中的this是global对象---window. 那上面的法则不是不对吗? 其实,在window里面调用函数,可以这样写.

function getName(){
    console.log("jimmy");
}
window.getName();  //jimmy
getName();  //jimmy

上面两种写法是完全等价的,只是一般比较懒,直接写成下面那一种了。

作为普通函数调用

上面已经说了,普通函数的this的不指定性,即,在使用之前函数的this都是不定的,直到函数执行的时候。
在es5中规定,当你的函数在全局中执行,该this会指向window.如果在严格模式下,则this为undefined

function name(){
    console.log(this);
}
console.log(name());  // undefined

通常,当你的函数作为普通函数被调用的时候,this指向的是window,这个已经说过了~

function getName(){
    console.log(this.name);
}
var obj = {
    name : "jimmy",
    getName:getName
}
obj.getName();  //jimmy

在事件执行的时候,this指向的是该元素的引用

123
//js document.querySelector(".name").onclick = function(){ console.log(this); } //得到的结果是.[object HTMLDivElement]

同样,加深印象。

构造器的调用

这其实很简单,就是使用new + funciton 创建的是一个对象,而不是一个函数.

function GetName(){
    this.name = "jimmy";
}
GetName.prototype.getName = function(){
    return this.name;
}
var get = new GetName();
get.name(); //jimmy
get.getName(); //jimmy

这里的this指向的就是getName.prototype上的。
但需要注意在构造器内不能显示的返回一个对象,否则你的实例化就会被破坏。

function GetName(){
    this.name = "jimmy";
    return {};  //显示返回一个对象
}
GetName.prototype.getName = function(){
    return this.name;
}
var name = new GetName();
console.log(name);  //{}
var name2 = GetName();
console.log(name2); //{}
//显示返回一个非对象
function GetName(){
    this.name = "jimmy";
    return "sam";  //返回非对象
}
GetName.prototype.getName = function(){
    return this.name;
}
var name = new GetName();
console.log(name); //["Object Object"]
var name2 = GetName();
console.log(name2);  //sam
call,apply调用

call和apply的区别,一个是传入参数为枚举,一个为数组
实际上,他们的用处还有扩展了函数的作用域

function getName(){
    console.log(this.name);
}
var obj = {
    name : "jimmy"
}
getName.call(obj);  //jimmy
//相当于
obj.getName = getName;
obj.getName();  //这一个执行过程

使用call || apply改变this的作用域是非常关键的.
this的丢失
所谓的this丢失一般指的就是函数中this的丢失. 因为函数中的this只有在执行的时候才会确定指向。

var getId = document.getElement;
getId("#name");  //这里会报错

上面的错误主要是因为,使用document.getElement时,this是指向document,在getElement里面会需要使用this上面的一系列方法,而上面的方式则和普通调用函数的方式一样,这时this的指向是全局的global,所以会造成有些方法使用不到. 这里可以改进:

var getId = (function(fn){
    return funciton(){  //返回函数
        return fn.apply(document,arguments);
    }
})(document.getElement);  //保存引用
console.log(getId("#name"));  

但其实上面写法还不如直接return好使.这里只是方便讲解.
而es5里面的bind函数应该算是一个将call和apply用到了点子上的方法。

var getName = function(){
  console.log(this.tagName);  //DIV
  var sam = function(){
    console.log(this.tagName);  //undefined
  }
  sam();
}
document.querySelector(".name").onclick = getName;

上面的问题其实已经说到过了,就是出在函数作为普通函数调用的时候,里面的this永远指向的是 被赋予的对象。比如sam。 上面getName函数在执行的时候this是指向document.querySelector(".name")的.所以不会有什么问题.
改进的办法就是将this保存作用域(闭包).

var getName = function(){
  var _this = this;
  var sam = function(){
    console.log(_this.tagName);  //DIV
  }
  sam();
}
document.querySelector(".name").onclick = getName;

由于闭包的长相完全是芙蓉姐姐,所以在es6中为了避免闭包的露脸加上了 箭头函数的feature.

var getName = function(){
  var sam =()=>{
    console.log(this.tagName);
  }
  sam();
}
document.querySelector(".name").onclick = getName;  //DIV

完美输出. 虽然这样会显得你比较牛逼,但是如果你把这个投入生产,保证leader分分钟切si 你。 md这么长.
这时候apply就完美登场了。

var getName = function(){
    console.log(this.tagName);
}
document.querySelector(".name").onclick = function(){
  getName.apply(this);
};

是不是感觉少了很多代码~ 其实还可以再次改进,使用bind.

document.querySelector(".name").onclick = getName.bind(document.querySelector(".name"));

但这样其实还不如使用apply. 还需要注意的是call和apply都会直接执行函数,而bind只是返回一个函数.
apply和call的用法还有一个,就是借用其他对象的方法.
比如Math.max();函数,本来他只能接受枚举的参数,但可以使用apply进行装换

var num = [1,2,3,4,3,22];
console.log(Math.max.apply(null,num));  //22

上面基本说明了apply和call的用处,但事实上,只要你用得好,apply和call的价值应该灰常大的。比如你还可以使用[].slice.call(arguments),用来将arguments类数组对象转化为一个真正的数组。
Ending~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78461.html

相关文章

  • javascript创建构造函数时作用域安全,即怎样保证一直都是构造函数

    摘要:在使用利用面向对象的思想创建类和对象时,通常是使用构造函数,工厂方式,原型方式,原型构造函数方式等。 在使用javascript利用面向对象的思想创建类和对象时,通常是使用构造函数,工厂方式,原型方式,原型构造函数方式等。构造函数其实就是使用一个使用new操作符调用函数,当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例,例如: function Person(na...

    Shihira 评论0 收藏0
  • 【译】怎样在java中定义一个抽象属性

    摘要:我们的引擎使用预定义的分隔符来连接日志中的信息,并存储在一个中。在抽象类中定义带参数的构造函数在抽象类中定义动态属性的第一种方法是定义一个参数的构造函数。 翻译:疯狂的技术宅原文:http://programmergate.com/def...本文首发微信公众号:充实的脑洞 Abstract关键字通常被用于类和方法,用来把某些行为的实现委托给子类。由于Java不支持抽象属性,如果你试图...

    aervon 评论0 收藏0
  • 怎样使用React Context API

    摘要:翻译疯狂的技术宅原文本文首发微信公众号欢迎关注,每天都给你推送新鲜的前端技术文章现在已经成为一个实验性功能,但是只有在中才能用在生产中。创建完成后,我们可以导入并用它来创建我们的,我们称之为。在巨大的宣传攻势下将会使变得过时。 翻译:疯狂的技术宅原文:https://www.toptal.com/react/... 本文首发微信公众号:jingchengyideng欢迎关注,每天都...

    anRui 评论0 收藏0
  • 怎样用JavaScript和HTML5 Canvas绘制图表

    摘要:饼状图将数据用切割成份的圆来展示。至于半径,我们用宽度的一半与高度的一半的较小值,因为我们不想让饼状图超出。结果看起来如下这样绘制圆环图我们已经看到如何创建饼状图。怎样画洞呢我们可以画一个白色的圆在饼状图上。 showImg(https://segmentfault.com/img/bVObDh?w=850&h=362); 原文:https://code.tutsplus.com/zh...

    doodlewind 评论0 收藏0
  • 怎样用JavaScript和HTML5 Canvas绘制图表

    摘要:饼状图将数据用切割成份的圆来展示。至于半径,我们用宽度的一半与高度的一半的较小值,因为我们不想让饼状图超出。结果看起来如下这样绘制圆环图我们已经看到如何创建饼状图。怎样画洞呢我们可以画一个白色的圆在饼状图上。 showImg(https://segmentfault.com/img/bVObDh?w=850&h=362); 原文:https://code.tutsplus.com/zh...

    wizChen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<