我有以下代码:
//Main Entry Point.
start() {
this.init();
this.gameLoop();
}
//Init, runs only once.
init() {
let initalEntity1: Entity = new Entity(10, 10, Gender.female);
let initalEntity2: Entity = new Entity(60, 60, Gender.male);
console.log("There are " + this.Entities.length + " Items in the entities Array")
this.Entities.push(initalEntity1, initalEntity2);
console.log("There are " + this.Entities.length + " Items in the entities Array")
}
gameLoop() {
console.log("Performing a Game Loop");
requestAnimationFrame(this.gameLoop);
//MAIN LOOP THROUGH ENTITIES
for (let i in this.Entities) {
this.Render.drawEntitysToScreen(this.Entities[i].EntityPosition, this.Entities[i].gender);
}
}
它进入start()
罚款,并执行所有init()
功能。它们继续运行到gameloop()
,它将运行一次,但是重新触发要被调用为Canvas框架的函数的行requestAnimationFrame(this.gameLoop);
导致以下错误:
TypeError: this is undefined
尝试requestAnimationFrame(gameLoop);
但它会导致打字稿编译器感到不安......
答案 0 :(得分:1)
当您在this.gameLoop()
内拨打start
时,this
内部的gameLoop
的值将是gameLoop
所属的类,因为您致电gameLoop
作为this
(该类)的属性。
传递函数引用时,this
的值可能是从其他地方调用函数时的任何值。
解决方案1 |使用Function.prototype.bind
bind
时,{p> this
requestAnimationFrame
的值。通过这样做你明确地说:
让bind
的参数在this
的任何调用中都是gameLoop
,无论调用方式如何,或者调用它的位置。 < / p>
requestAnimationFrame(this.gameLoop.bind(this));
请注意,bind会返回新函数,因此仍然是类属性的原始gameLoop
函数保持不变。
解决方案2 |使用arrow function
定义箭头函数以最终执行对gameLoop
而非requestAnimationFrame
的调用。箭头函数中的this
值是静态的,并且是从包含函数声明的执行上下文继承的。
requestAnimationFrame(() => this.gameLoop());
答案 1 :(得分:1)
这是由于this
绑定在javascript中的工作原理。您将this.gameLoop
传递给requestAnimationFrame
的方式实际上是传递未绑定的gameLoop
函数,因此在调用它时,它已失去对其this
的引用。< / p>
这个问题有很多可能的解决方案:
您可以将this.gameLoop
绑定到类构造函数内部的this
,如下所示:
constructor() {
this.gameLoop = this.gameLoop.bind(this);
}
您可以将this.gameLoop
绑定到this
,作为gameLoop
方法定义的一部分。而不是像gameLoop
那样定义
gameLoop() {
如果您改为使用
gameLoop = () => {
它将自动绑定到this
。这是使用胖箭头进行函数声明的属性:它自动执行与函数声明中存在的this
的绑定。
您可以更改gameLoop
到requestAnimationFrame
的方式:
requestAnimationFrame(() => this.gameLoop());
这再次利用了箭头函数执行的自动this
绑定,但不是将其作为类方法声明的一部分,而是在您需要绑定时可以简单地执行它。
但请注意,这样做意味着每次调用gameLoop
时都会创建一个新函数。