js中this指向问题全解析_蓝戒的博客


js中this指向问题全解析

通常而言在JS中, this的值取决于调用的模式, 而JS中共有4中调用模式:
1.方法调用模式
当一个函数被保存为对象的一个属性时, 我们称它为一个方法, 当一个方法被调用时, this指向该对象, 如:

var obj = {
value: 1,
getValue: function() {
alert(this.value);
}
};
obj.getValue(); // 输出1, 此时的this指向obj

注意: 该模式中, this到对象的绑定发生在方法被调用的时候.

2、函数调用模式
当一个函数并非一个对象的属性时, 它被当作一个函数来调用, 此时的this指向全局对象(window), 如:

window.value = 1;
function getValue() { alert(this.value); }
getValue(); // 输出1, 此时的this指向window.

3、构造器调用模式
结合new前缀调用的函数被称为构造器函数, 此时的this指向该构造器函数的实例对象, 如:

function show(val) {
this.value = val;
};
show.prototype.getVal = function() {
alert(this.value);
};
var func = new show(1);
func.getVal(); // 输出1
alert(func.value) // 输出1
// 从上面的结果, 可以看出, 此时的this指向了func对象.

4、apply/call调用模式以及bind
apply和call方法可以让我们设定调用者中的this指向谁, 如:

var fun = function(str) {
this.status = str;
}
fun.prototype.getStatus = function() {
alert(this.status);
}
var obj = {
status: "loading"
};
fun.prototype.getStatus.apply(obj); // 输出"loading", 此时getStatus方法中的this指向了obj

5、特殊情况
setInterval和setTimeout中传入函数时,函数中的this会指向window对象。

var num = 0;
function Obj (){
this.num = 1,
this.getNum = function(){
console.log(this.num);
},
this.getNumLater = function(){
setTimeout(function(){
console.log(this.num);
}, 1000)
}
}
var obj = new Obj;
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//0  打印的为window.num,值为0

从上述例子中可以看到setTimeout中函数内的this是指向了window对象,这是由于setTimeout()调用的代码运行在与所在函数完全分离的执行环境上. 这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。

但是在setTimeout中传入的不是函数时,this则指向当前对象,如下例:

var num = 0;
function Obj (){
this.num = 1,
this.getNum = function(){
console.log(this.num);
},
this.getNumLater = function(){
setTimeout(console.log(this.num), 1000)
}
}
var obj = new Obj;
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

从以上两个例子可以看出,当在setTimeout中传入的参数为函数时,函数内部的this才会指向window对象。

当在setTimeout中传入了一个函数,若想要让this指向正确的值,可以使用的二种常用方法来使this指向正确的值:
1.将当前对象的this存为一个变量,定时器内的函数利用闭包来访问这个变量
如下:

var num = 0;
function Obj (){
var that = this; //将this存为一个变量,此时的this指向obj
this.num = 1,
this.getNum = function(){
console.log(this.num);
},
this.getNumLater = function(){
setTimeout(function(){
console.log(that.num); //利用闭包访问that,that是一个指向obj的指针
}, 1000)
}
}
var obj = new Obj;
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

这种方法是将当前对象的引用放在一个变量里,定时器内部的函数来访问到这个变量,自然就可以得到当前的对象。

2.利用bind()方法

var num = 0;
function Obj (){
this.num = 1,
this.getNum = function(){
console.log(this.num);
},
this.getNumLater = function(){
setTimeout(function(){
console.log(this.num);
}.bind(this), 1000) //利用bind()将this绑定到这个函数上
}
}
var obj = new Obj;
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

bind()方法是在Function.prototype上的一个方法,当被绑定函数执行时,bind方法会创建一个新函数,并将第一个参数作为新函数运行时的this。在这个例子中,在调用setTimeout中的函数时,bind方法创建了一个新的函数,并将this传进新的函数,执行的结果也就是正确的了
当然如果使用call或apply方法来代替bind方法,得到的结果也是正确的,但是call方法会在调用之后立即执行,那样也就没有了延时的效果,定时器也就没有用了,所以推荐使用上述两种方法来将this传进setTimeout和setInterval中。

ES6的箭头函数

此外,使用ES6的箭头函数可以确保this指向当前作用域的对象

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

参考资料:

1.http://blog.csdn.net/babybk/article/details/51272790
2.http://www.jb51.net/article/102232.htm
3.http://www.cnblogs.com/long-long/p/6741083.html

本文固定链接: http://www.webzsky.com/?p=1127 | 蓝戒的博客

cywcd
该日志由 cywcd 于2017年07月11日发表在 javascript 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: js中this指向问题全解析 | 蓝戒的博客
关键字:

js中this指向问题全解析:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter
来自的朋友,欢迎您 点击这里 订阅我的博客 o(∩_∩)o~~~
×