函数中this的指向问题特别容易让人迷糊,这里用示例来指点迷津,走出迷茫。
常规函数下的this指向
1. 纯粹的函数调用
function test(name) {
console.log(name)
console.log(this)
}
test('zjcopy') ;
test.call('zjcopy', 'cuclife-2') ;
test.call(false, 'cuclife-3') ;
test.call(null, 'cuclife-4') ;
test.call(undefined, 'cuclife-5')
说明:
在函数没有调用的时候,this的值是无法确定。 普通的函数调用,this指向的是window窗口。call方法接收的第一个参数就是this,当第一个参数指定为null或者undefined时候,this指向window。
2. 对象中的函数调用
const obj = {
name: 'zjcopy.com',
greet: function() {
console.log(this.name)
}
}
obj.greet() //第一种调用方法
obj.greet.call(obj) //第二种调用方法等同于第一种
obj.greet.call({name: 'cuclife.com'}) //将this指定为一个对象
不同于纯粹的函数,调用的主体是window。这里面指定了用对象来调用自身,所以this指向了name:“zjcopy.com”. 使用call指向name的时候,name值做了更改,所以显示结果为cuclife.com .
3. 构造函数中this
function Test() {
this.name = 'zjcopy.com'
this.age=function() { console.log(this.name) }
}
let pp = new Test()
console.log(typeof pp)
console.log(pp)
console.log(pp.age)
console.log(pp.age())
console.log(pp.age.call({name : 'cuclife.com'}))
console.log(pp.name)
说明:
构造函数里的this稍微有点特殊,每个构造函数在new之后都会返回一个对象,这个对象就是this。
4. window.setTimeout()和window.setInterval()中函数的调用
window.setTimeout()和window.setInterval()的函数中的this有些特殊,里面的this默认是window对象。
简单总结一下:函数完整的调用方法是使用call方法,包括test.call(context, name)和obj.greet.call(context,name),这里的context就是函数调用时的上下文,也就是this,只不过这个this是可以通过call方法来修改的;构造函数稍微特殊一点,它的this直接指向new之后返回的对象;window.setTimeout()和window.setInterval()默认的是this是window对象。
箭头函数下的this指向
箭头函数会默认帮我们绑定外层this的值,所以在箭头函数中this的值和外层的this是一样的。
默认绑定外层this, 不能用call方法修改里面的this
const obj = {
a: function() { console.log(this) } ,
b: () => {
console.log(this)
}
}
obj.a();
obj.b()
obj.b.call('zjcopy')
在使用箭头函数的例子里,因为箭头函数默认不会使用自己的this,而是会和外层的this保持一致,最外层的this就是window对象。为了减少this的复杂性,箭头函数无法用call方法来指定this。
综合案例
let obj = {
name: ' zjcopy.com',
age: 3,
say1() {
setTimeout(function() {
console.log("第一个");
console.log( this.name);
}, 500)
},
say2() {
let self = this;
setTimeout(function() {
console.log("第二个" + self.name);
}, 500)
},
say3() {
setTimeout(() => {
console.log("第三个" + this.name);
}, 500)
}
}
obj.say1();
obj.say2();
obj.say3();