我们通常讨论的this指向指的是函数中的this指向,如果this不在函数里面,那就要判断当前环境。node环境this指向空对象{},浏览器环境this指向window(严格模式是undefined)
把对象分成两个部分,对象的名字和对象的数据。对象的名字放在栈中,对象的数据放在堆中。
一句话总结this:
this是函数的自有变量,指向了保存在堆中的某个对象的数据
在 JavaScript 中,每个函数都有一个特殊的变量 this。这个变量在函数被调用时被自动创建。
这句话非常重要!!!重要的话说三次!!!
这个变量在函数被调用时被自动创建
这个变量在函数被调用时被自动创建
这个变量在函数被调用时被自动创建
所以说this指向跟这个函数是怎么被调用的是很关键的。
确定函数中的this指向谁(哪个对象的数据),完全取决于是如何调用这个函数的
常见的的四种调用形式:
1.通过new关键字创建的对象,this指向创建的对象即实例。
2.通过call,apply,bind,this指向我们给到的对象(显示绑定)
3.函数作为A对象的方法调用,this指向A对象。(隐式绑定)
4. 以上三种都不是,则指向undefined
补充:箭头函数没有this
所以箭头函数中的this指向,不要去用上面的方法判断,而是看词法作用域
举个栗子:
下面逐个解释
1. obj.fun()
fun函数是作为obj对象的方法调用,this指向obj对象,即上述说的第三种情况,所以输出Alice很好理解。
2. obj.funCB()
funCB函数作为obj对象的方法调用,this指向obj对象。funCB下的setTimeout函数中的匿名函数,在调用时不属于前三种情况,所以是第四种undefined。
3. obj.funCBArrow()
funCBArrow函数作为obj对象的方法调用,this指向obj对象。funCBArrow下的setTimeout函数中的匿名箭头函数,由于是箭头函数,箭头函数本身没有this,所以继承自funCBArrow的this,所以指向obj对象。
4. obj.funCBArrow2()()
funCBArrow2函数作为obj对象的方法调用,this指向obj对象。obj.funCBArrow2()返回的是一个匿名函数,obj.funCBArrow2()()调用的就是function(){}匿名函数。调用这个匿名函数不属于前三种情况,所以是第四种undefined,即匿名函数this指向undefined。那么匿名函数下的setTimeout中的箭头函数this继承自匿名函数,所以也指向undefined。
5. obj.funCBArrow3()()
funCBArrow3函数作为obj对象的方法调用,this指向obj对象。obj.funCBArrow3()返回的是一个匿名箭头函数,obj.funCBArrow3()()调用的就是()=>{}匿名箭头函数。由于匿名函数中没有this,所以继承自funCBArrow3的this即指向obj对象,同理setTimeout中的匿名箭头函数的this也继承自上一个匿名箭头函数的this所以指向obj对象。
代码块,可以复制这段js去测试一下
const obj = {
name: "Alice",
fun() {
console.log(`Hello, my name is ${this.name}`);
},
funCB() {
console.log(`Hi, my name is ${this.name}`);
setTimeout(function () {
console.log(`Hello, my name is ${this.name}`);
}, 1000);
},
funCBArrow() {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}`);
}, 1000);
},
funCBArrow2() {
return function () {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}`);
}, 1000);
};
},
funCBArrow3() {
return () => {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}`);
}, 1000);
};
},
};
obj.fun();//Hello, my name is Alice
obj.funCB();//Hi, my name is Alice Hello, my name is undefined
obj.funCBArrow();//Hello, my name is Alice
obj.funCBArrow2()();//Hello, my name is undefined
obj.funCBArrow3()();//Hello, my name is Alice
看看在类中原型上的方法,也是一样的判断方式