1

目录

一.理解this指针意义
二.用call(),apply(),bind()解决指针指向问题
三.bind()的使用场景与少用之处

一.理解this指针意义

让我们先理解好this指针的定义:

this引用的是函数执行的环境对象

this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的

通俗地讲,就是谁调用this,this就指向谁,我们分类举例

举例前先看下本文会一直用到的变量及定义的函数

var theName = "Joe";    //全局变量

function showName() {
   var theName = "Li";
   alert(this.theName);
}

1.全局直接调用方法

showName();    //弹出“Joe”

因为是window对象调用showName(),所以this指向window啦,故弹出"Joe"

2.对象中调用全局下的方法

var student1 = {
   theGrade : 100,
   theName : "Han",
   showName : showName,
   showGrade : function () {
      alert(this.theGrade);
   }
};
student1.showName();//弹出“Han”
student1.showGrade();//弹出“100”

因为是在student1对象调用函数,故弹出的是对应student1对象中的"Han"和“100”啦

3.对象中调用其他对象的方法

var student2 = {
   theGrade: 60,
   showGrade: student1.showGrade
};
student2.showGrade();    //弹出"60"

即使student2对象调用了student1对象下的方法showGrade(),因为是student2对象调用,故弹出的仍是student2的"60"

4.对象的方法赋给全局变量执行

var outFunction = student1.showGrade;
outFunction();//弹出“undefined”

将sutdent1对象的函数赋值给oufFuncction,而outFunction是在window对象下调用的,故弹出“undefined”

5.构造函数下的this指针

function setStudent() {
   this.theName = "Ming";
}
var student3 = new setStudent();
alert(student3.theName);//弹出“Ming”,new改变this指向

构造函数下,new改变了指针指向,指向了student3

6.事件监听中创建闭包的this指针

关键:闭包保存创建时的环境!!!

举个例子

为了更好理解闭包与指针的关系,我们先定义一个全局变量,一个函数,和一个对象

var example = 'window';//全局变量

function showExample() {
   console.log(this.example);
}

var exampleObject = {
   example : 'Object',
   showExample_in_Object : function (arg1, arg2) {
      console.log(this.example);
      console.log(arg1,arg2)
   }
};

接着,我们设置一个事件监听来说明问题:

//事件监听
var btn = document.getElementById("btn");
btn.onclick = function (ev) {
   console.log(this); //this指向按钮,执行匿名函数的是btn
   this.example = 'ele';
   console.log(this.example);//弹出"ele"
   showExample(); //闭包保存函数创建时的环境,故this指向window对象 
   exampleObject.showExample_in_Object();//this指向exampleObject
};

结果:

clipboard.png

接下来分段说明各个指针

其中

    this.example = 'ele';

    console.log(this.example);

其中的this指向btn,所以显示的是‘ele’

    showExample();      

    exampleObject.showExample_in_Object();    

匿名函数中为闭包,闭包保存函数创建时的环境,故this分别指向window和exampleObject

补充对闭包中this的理解:https://segmentfault.com/q/10...

以上是部分this指针的理解

如果我在事件监听中想要减少代码重复,或者是调用其他对象的属性呢?

如果我想用btn.addEventListener()时指向的某个特定对象呢?

这就可以引出下面call(),apply()与bind()的应用了

7.函数中自执行函数指向

function User(id){
    this.id = id;
}
User.prototype.test = function(){
    console.log(this);//指向b对象

   (function(){
    console.log(this) //指向window
})()
}
var a = new User('a')
a.test(); 

因为自执行函数是由window执行的
如果此时使用箭头函数

function User2(id){
    this.id = id;
}
User.prototype.test = function(){
    console.log(this); //指向b对象

   (() =>{
    console.log(this) //指向b对象
})()
}
var b = new User2('b');
b.test(); 

因为箭头函数不会绑定this,所以指向上一层的b对象

二.用call(),apply(),bind()解决指针指向问题

1.call()与apply()

call()与apply()的作用都是在特定的作用域中调用函数,实际上等于设置函数体内设置this对象的值

简单地说,就是可以改变函数的执行环境

call()与allpy()效果相同,仅是传参形式不同,如下所示

call():

fun.call(thisArg, arg1, arg2, ...)

thisArg : fun函数运行时指定的this值

arg1,arg2,.. (可选):指定的各个参数
apply():

func.apply(thisArg, [argsArray])

thisArg : fun函数运行时指定的this值

[argsArray](可选) : 传参数组或者传参类数组

下面直接看例子吧

我们以上面的例子进行修改,为了对比传参的形式,我们对showExample函数添加两个参数

function showExample(arg1,arg2) {
   console.log(this.example);
   console.log(arg1,arg2);
}

接下来便是btn的点击事件函数修改,我们令showExample函数指向exampleObject

//call与apply的应用
btn.onclick = function (ev) {
   showExample.call(exampleObject,111,222); //弹出'Object' ,111与222是传参示例
   showExample.apply(exampleObject,[111,222]); //弹出'Object' ,[111,222]是传参示例
};
弹出'Object' ,111与222是传参示例
   showExample.apply(exampleObject,[111,222]); //弹出'Object' ,[111,222]是传参示例
};

clipboard.png

如上,通过call()与apply()的应用,可以改变函数的指向而多次运用

如果我想便于调试想使用ele.addEventListener()嘞?

这就要用上bind()方法了

2.bind()的运用

fun.bind(thisArg[, arg1[, arg2[, ...]]])

MDN : bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值, ,在调用新函数时,在任何提供之前提供一个给定的参数序列。

我们再举个简单的例子,将exampleObject简单修改下

var exampleObject = {
   example : 'Object',
   showExample_in_Object : function (arg1, arg2) {
      console.log(this);
      console.log('example:'+ this.example);
      console.log('arg1:' + arg1);
      console.log('arg2:' + arg2);
   }
};

并把showExample_in_Object()函数添加给btn

注意这里的是函数,不是闭包!

btn.addEventListener('click',exampleObject.showExample_in_Object);

控制台显示如下

clipboard.png

            

可以看出this指向的是btn,而无法满足我们使用exampleObject中属性的需要,同时也无法进行传参(用call()与apply()就直接执行函数了!)

(这里的没有对第一个参数arg1进行传参,故默认显示MouseEvent对象)

这时我们可以用bind()方法创建一个新的函数,并让其指针指向exampleObject,并传两个新的参数进去

btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));

clipboard.png

当当~指针指向了exampleObject,传参也成功了~

另外,这里也有个可以不使用bind()的方法,就是也用闭包

btn.addEventListener('click',function () {
    exampleObject.showExample_in_Object(111,222);
});

结果一样,但这种方法不利于代码的维护,同时也无法指向特定的对象    

三.bind()的使用场景与少用之处

使用场景:主要用于如上的事件监听,以及setTimeout()setInterval()

少用之处:被绑定的函数与普通函数相比有更多的开销,它们需要更多的内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用

以上,如有不对之处,请大家指教

参考资料:

    彻底理解this指针:    https://www.cnblogs.com/pssp/...

    MDN:bind():    https://developer.mozilla.org...

    MDN:apply():https://developer.mozilla.org...

    MDN:call():    https://developer.mozilla.org...

    《JavaScript高级程序设计(第3版)》

    《JavaScript语言精粹》


Jonithan
249 声望12 粉丝

GitHub:[链接]