class A {
constructor() {
this.b = 1;
};
c() {
console.log(this.b);
};
d() {
setTimeout(this.c, 1000);
};
const a = new A();
a.d(); // undefined
在构造函数A中,定义了属性b,赋值为1。在A的原型链上定义了方法c和方法d,方法c打印属性b,方法d设置定时器,1秒后调用方法c。实例化A保存到a, 调用实例中的d方法,输出undefined。
在构造函数中,将c方法直接作为回调传入定时器,此时c方法并未执行,而是在实例a调用d方法的时候在定时器内部执行的,此时定时器的执行环境上下文是window,在全局中并未定义c,所以为undefined;
如果需要在调用的时候能在实例中找到c,有三种办法:
一、用闭包将this保存起来:
首先什么是闭包?一句话:在一个函数内部return一个函数,被return的这个函数引用了外面那个函数中定义的变量,导致这个变量永远不会被销毁,也不会被改变:
function closure() {
var canNotBeChangedByContext = 1;
return function(arg) {
console.log(canNotBeChangedByContext += arg);
};
};
closure()(5); //6
closure()(5); //6
当然也有办法可以破解,将该函数赋值给一个变量保存起来,再连续调用那个变量即可:
function closure(){
var canNotBeChangedByContext = 1;
return function(arg){
console.log(canNotBeChangedByContext += arg);
};
};
var breakClosure = closure();
breakClosure(5); // 6
breakClosure(5); // 11
理解了什么是闭包,我们就可以在c方法中,通过闭包,将this永久地保存起来,供下面被return的函数引用,不论它是在什么样的执行环境:
class A {
constructor() {
this.b = 1;
};
c() {
const self = this;
return function() {
console.log(self.b);
}
};
d() {
setTimeout(this.e(), 1000)
}
};
const a = new A();
a.d(); // 1
二、用箭头函数:
箭头函数没有像function关键字的函数那样,它不会根据执行环境而改变this的指向,在定义的时候取到的this是什么,就不会再改变。
class A {
constructor() {
this.b = 1;
};
c() {
console.log(this.b);
};
d() {
const self = this;
setTimeout(() => console.log(this.b), 1000);
};
};
const a = new A();
a.d(); // 1
三、用Function的bind方法:
在调用bind方法的时候,重新创建了一个函数,且该函数的this指向已被设置为传入bind方法的第一个参数。这里我们传的是this,所以当这个新的函数在计时器里被调用的时候,取到的this是已经被保存的this,指向该构造函数的实例。
class A {
constructor() {
this.b = 1;
};
c() {
console.log(this.b);
};
d() {
const self = this;
setTimeout(this.c.bind(this), 1000);
};
};
const a = new A();
a.d(); // 1
网友评论