gpt4 book ai didi

Javascript 对象属性被 setInterval 调用的方法报告为未定义

转载 作者:行者123 更新时间:2023-11-29 22:58:24 26 4
gpt4 key购买 nike

我正在努力研究 Javascript,并希望制作一个简单的 Web 小程序,可以通过按钮启用和禁用,启用后可以绘制内容。为了编写干净(更)的代码,我想为此使用一个对象。带有按钮的页面设置是

<div>
<input type="button" name="runbutton" value="Run" onclick="game.run();"/>
<input type="button" name="resetbutton" value="Reset" onclick="game.reset();"/>
</div>

<script>
//...
</script>

javascript代码是

function Game() {
this.runs = false;
this.run = function() {console.log('run...'); this.runs = true;};
this.reset = function() {console.log('reset...'); this.runs = false;};
this.update = function() {console.log('updating... runs:', this.runs);};
};
var game = new Game();
game.reset();
setInterval(game.update, 300);

所以它是一个对象定义(游戏),其中一个实例(游戏)具有一个 bool 属性(运行)和三个方法。一个运行它,一个停止运行,一个 update() 方法报告它是否运行。 update() 使用 setInterval 每 300 毫秒重复一次。

问题:来自 update() 的控制台日志将 this.runs 的值报告为未定义,而不是 false 或 true。当我打开控制台并暂停它以检查变量时,它会将 game.runs 正确报告为 false 或 true。此外,当我将 console.log() 调用添加到 run() 和 reset() 报告 this.runs 的值之前和之后设置它时,它似乎正确报告 true 和 false。所以问题似乎出在 update() 的某个地方。好像用错了“这个”。也许 setInterval 不能用在方法上?

我为代码尝试了另外两种语法,但它们似乎有完全相同的问题:

var game = {
runs: false,
run: function() {console.log('run...'); this.runs = true;},
reset: function() {console.log('reset...'); this.runs = false;},
update: function() {console.log('update... runs:', this.runs);}
};
game.reset();
setInterval(game.update, 300);

以及在对象中设置 setInterval 的版本:

var game = {
runs: false,
i: undefined,
run: function() {console.log('run...'); this.runs = true; this.i = setInterval(this.update, 300);},
reset: function() {console.log('reset...'); this.runs = false; clearInterval(this.i);},
update: function() {console.log('update... runs:', this.runs);}
};
game.reset();

同样的问题。

这是怎么回事?为什么 update() 将 this.runs 报告为未定义?我是否更正了方法中的“this”在所有情况下确实指的是游戏实例?我不应该在方法上使用 setInterval,而是调用全局函数吗?

最佳答案

在 JavaScript 中,this 的规则有些复杂;相关的是,如果作为方法调用,存储在对象属性中的非箭头函数可以将 this 分配给对象。让我们解析一下:

  • game.updategame 对象的属性,✅
  • 它包含一个非箭头函数,✅
  • 它作为一个方法被调用... ❌

“作为方法调用”是什么意思?这意味着您在 object.property 语法上调用函数,如下所示:game.update(...)

但是,game.update 作为参数传递,它失去了与 game 的连接。您的代码相当于:

var func = game.update;
setInterval(func, 300);

其中 setTimeout 将只调用 func()。这意味着 game.update 被作为函数而不是方法调用,并且 this 在被调用时不会被设置为 game

典型的解决方法是:

  • 将接收器绑定(bind)到函数。这是在上述方法调用之外设置 this 的另一种方法:如果一个函数绑定(bind)到接收者对象,它总是会在调用时将 this 设置给它。你会把它写成:

    setInterval(game.update.bind(game), 300)

    在 React 中经常使用的一个变体是在定义的地方将函数显式绑定(bind)到接收器:

    this.update = function() {console.log('updating... runs:', this.runs);};
    this.update = this.update.bind(this);
  • 通过以下任一方式显式使用方法调用:

    setInterval(() => game.update(), 300);
    setInterval(function() { game.update(); }, 300);
  • this 使用箭头函数按词法定义。由于 this 是定义函数时的游戏对象,将它们变成箭头函数将始终将 this 设置为该游戏对象。这需要在定义点而不是调用点进行更改:

    this.update = () => {console.log('updating... runs:', this.runs);};

关于Javascript 对象属性被 setInterval 调用的方法报告为未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56144301/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com