目录
一.理解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
};
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/7cb6e4127bee51e614489cfe374f3314.png)
接下来分段说明各个指针
其中
this.example = 'ele';
console.log(this.example);
其中的this指向btn,所以显示的是‘ele’
而
showExample();
exampleObject.showExample_in_Object();
在匿名函数中为闭包,闭包保存函数创建时的环境,故this分别指向window和exampleObject
补充对闭包中this的理解:https://segmentfault.com/q/1010000004648772
以上是部分this指针的理解
如果我在事件监听中想要减少代码重复,或者是调用其他对象的属性呢?
如果我想用btn.addEventListener()时指向的某个特定对象呢?
这就可以引出下面call(),apply()与bind()的应用了
二.用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]是传参示例
};
![](https://i-blog.csdnimg.cn/blog_migrate/d8783888346b8164514bc879cca3d3da.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);
}
};
注意这里的是函数,不是闭包!
btn.addEventListener('click',exampleObject.showExample_in_Object);
控制台显示如下
![](https://i-blog.csdnimg.cn/blog_migrate/2a211693f8476a33710fdd145f06eaa0.png)
可以看出this指向的是btn,而无法满足我们使用exampleObject中属性的需要,同时也无法进行传参(用call()与apply()就直接执行函数了!)
(这里的没有对第一个参数arg1进行传参,故默认显示MouseEvent对象)
这时我们可以用bind()方法创建一个新的函数,并让其指针指向exampleObject,并传两个新的参数进去
btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));
![](https://i-blog.csdnimg.cn/blog_migrate/22011ae5730b96da73999fa24d985d52.png)
当当~指针指向了exampleObject,传参也成功了~
另外,这里也有个可以不使用bind()的方法,就是也用闭包啦
btn.addEventListener('click',function () {
exampleObject.showExample_in_Object(111,222);
});
结果一样,但这种方法不利于代码的维护,同时也无法指向特定的对象
三.bind()的使用场景与少用之处
使用场景:主要用于如上的事件监听,以及setTimeout()和setInterval()
少用之处:被绑定的函数与普通函数相比有更多的开销,它们需要更多的内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用
以上,如有不对之处,请大家指教~
参考资料:
彻底理解this指针:
https://www.cnblogs.com/pssp/p/5216085.html
MDN:bind():
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
MDN:apply():
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
MDN:call():
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
《JavaScript高级程序设计(第3版)》
《JavaScript语言精粹》