`this`的属性在setTimeout中未定义

时间:2018-05-20 01:57:05

标签: javascript this

class Simulator {
  constructor() {
    this.gates = Array();
    this.gates.push(new AndGate(200, 200));
  }
  initialize() {
    let canvas = document.getElementById('board');
    canvas.width = 800;
    canvas.height = 500;
    canvas.setAttribute("style", "border: 1px solid black");
    this.gates.push(new AndGate(100, 100));
  }
  run() {
    setTimeout(this.onLoop, 1000);
  }
  onLoop() {
    for (let gate of this.gates) {
      gate.render();
    }
  }
}
let sim = new Simulator();
sim.initialize();
sim.run();

出于某种原因,我的TypeScript类的JS转换版本会在onLoop函数中引发错误。它会报告TypeError: this.gates is undefined。但是,如果我访问sim(模拟器对象)并手动访问其属性,则定义它。我可以从控制台手动运行onLoop代码。

2 个答案:

答案 0 :(得分:3)

当函数通过引用传递时,它们将失去对this的引用。在致电setTimeout时,您将失去此引用。

函数有一个bind()方法,它基本上返回一个新函数,并带有对this的更正引用。

这样称呼:

setTimeout(this.onLoop.bind(this), 1000)

或者,您也可以传递内嵌箭头功能。箭头功能不会丢失this上下文。

setTimeout(() => this.onLoop(), 1000)

答案 1 :(得分:1)

this.onLoop内调用setTimeout时,onLoop内的调用上下文是 window ,因为setTimeout是<{1}}的函数em> window 对象。您可以使用调用 onLoop的箭头功能修复此问题,而不是直接传递onLoop

&#13;
&#13;
class Simulator {
  constructor() {
    this.gates = Array();
    //this.gates.push(new AndGate(200, 200));
  }
  initialize() {
    //let canvas = document.getElementById('board');
    //canvas.width = 800;
    //canvas.height = 500;
    //canvas.setAttribute("style", "border: 1px solid black");
    // this.gates.push(new AndGate(100, 100));
    this.gates.push({ render: () => console.log('rendered') });
  }
  run() {
    setTimeout(() => this.onLoop(), 1000);
  }
  onLoop() {
    for (let gate of this.gates) {
      gate.render();
    }
  }
}
let sim = new Simulator();
sim.initialize();
sim.run();
&#13;
&#13;
&#13;

或者通过将this函数的onLoop上下文绑定到实例化对象:

&#13;
&#13;
class Simulator {
  constructor() {
    this.gates = Array();
    //this.gates.push(new AndGate(200, 200));
  }
  initialize() {
    //let canvas = document.getElementById('board');
    //canvas.width = 800;
    //canvas.height = 500;
    //canvas.setAttribute("style", "border: 1px solid black");
    // this.gates.push(new AndGate(100, 100));
    this.gates.push({ render: () => console.log('rendered') });
  }
  run() {
    setTimeout(this.onLoop.bind(this), 1000);
  }
  onLoop() {
    for (let gate of this.gates) {
      gate.render();
    }
  }
}
let sim = new Simulator();
sim.initialize();
sim.run();
&#13;
&#13;
&#13;