目录
一.理解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
};
结果:
接下来分段说明各个指针
其中
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]是传参示例
};
如上,通过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);
控制台显示如下
可以看出this指向的是btn
,而无法满足我们使用exampleObject中属性的需要,同时也无法进行传参(用call()与apply()就直接执行函数了!)
(这里的没有对第一个参数arg1进行传参,故默认显示MouseEvent对象)
这时我们可以用bind()方法创建一个新的函数
,并让其指针指向exampleObject
,并传两个新的参数进去
btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));
当当~指针指向了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语言精粹》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。