3

我是 JavaScript 新手。因此,这个问题有点令人困惑。我试图简单地定义一个计数器并在类方法中递增它,但它的行为不像我期望的那样。专门console.log(this.tick_count);打印undefined

JavaScript:

function Game() {
    this.fps = 50;
    this.ticks = 3;
    this.current_time = (new Date).getTime();
    this.draw_object = document.getElementById('game_canvas').getContext('2d');
    this.tick_count = 0;
}

Game.prototype.update = function (time) {
    this.current_time = time;
}

Game.prototype.draw = function () {
    this.draw_object.fillRect(10, 10, 55, 50);
}

Game.prototype.run = function () {
    self.setInterval(this.tick, 1000 / (this.fps * this.tick));
}

Game.prototype.tick = function () {
    this.tick_count++;
    console.log(this.tick_count);
}

function start_game() {
    var game_object = new Game();
    game_object.run();
}

HTML:

<body onload="start_game()">
    <canvas id="game_canvas" width="1024" height="1024"></canvas>
</body>

来自 Python 背景,我觉得这种行为很奇怪。我应该如何正确设置我的类变量?

4

4 回答 4

10

这就是正在发生的事情。

本质上,您tick的功能不再在game_object对象的上下文中运行。从 Python 背景来看,这可能听起来很奇怪,但基本上该this对象被设置为其他东西。

那么它设置成什么?简单,window对象,我们怎么知道这个?因为setInterval的上下文是window对象。

将示例作为代码移动,下面的格式将不正确

绑定示例

setInterval(this.tick.bind(this), 1000 / (this.fps * this.tick)); //Native (JS v1.8+)
$.proxy(this.tick, this); //jQuery
_.bind(this.tick, this); //underscore / lodash

显式上下文示例

Game.prototype.run = function () {  
    var _this = this;  
    setInterval(function() {  
        //So what is this at the moment? window.
        //Luckily we have a reference to the old this.
        _this.tick();  
    }, 1000 / (this.fps * this.tick));  
 };

你可以通过这两种方式来解决。

  1. 将您的函数绑定到您希望它在Bind JS v1.8上的对象(因为您正在使用画布,这不应该成为问题。
  2. 使用其上下文显式调用该方法。(看上面)
于 2013-09-26T16:35:10.703 回答
4

尝试

setInterval(this.tick.bind(this), 1000 / (this.fps * this.tick));
// without "self"

感谢 PSL 和 TJ 克劳德

于 2013-09-26T16:29:16.587 回答
2

这将起作用:

setInterval(this.tick.bind(this), 1000 / (this.fps * this.tick));

就像这样:

var self = this;
setInterval(function () {
    self.tick();
}, 1000 / (this.fps * this.tick));
于 2013-09-26T16:36:29.167 回答
0

即使已经回答了这个问题,我认为您需要了解this指的是什么。有关更多详细信息,请参阅此答案

如果您想使用闭包而不是绑定,您可以通过调用返回函数的函数(在当前运行的函数之外)来限制范围。这样您就可以最小化闭包可用的变量数量。听起来很复杂,但只需对您的代码稍作调整,您就可以做到:

Game.prototype.run = function () {
    //best not to define a closure here because the next variable
    //will be available to it and won't go out of scope when run
    //is finished
    var memoryEatingVar=new Array(1000000).join("hello world");;
    //note that this.tick(this) is not passing this.tick, it's invoking
    //it and the return value of this.tick is used as the callback
    //for the interval
    setInterval(this.tick(this), 1000 / (this.fps * this.tick));
}
//note the "me" variable, because the outer function Game.prototype.tick
//returns a inner function (=closure) the me variable is available in 
//the inner function even after the outer function is finished
Game.prototype.tick = function (me) {//function returning a function
  return function(){
    me.tick_count++;
    console.log(me.tick_count);
  }
}
于 2013-09-29T11:46:54.210 回答