访问实例方法时出现的JavaScript OO问题

JavaScript OO issue when accessing instance methods

本文关键字:JavaScript OO 问题 实例方法 访问      更新时间:2023-09-26

我使用了一些JavaScript中的OOP教程。一切似乎都很顺利,直到我遇到了下面这些……

Result of expression 'this.prepareFrame' [undefined] is not a function.

Ok。我使用prototype,并使用this关键字。

查看我的app.js页面在这里…

// Plain "main" function called by the html page, like <script>main()</script>. This works nicely:
    function main() {
    engine = new AbstractEngine();
    engine.init();
    }
// Next creates a new instance of my AbstractEngine class. Seems to work so far:
    function AbstractEngine() {}
// The init() method we called is defined afterwards:
    AbstractEngine.prototype.init = function() {
    this.initLoop();
    }
// remark: I'm using "this", and according to the debugger, "this" refers to the AbstractEngine we made an instance of.
// Next, we define the initLoop method:
    AbstractEngine.prototype.initLoop = function() {
    setInterval(this.tick, 1000 / 30);
    }
// Fine, everything works fine so far. Now get to define the "tick" method:
    AbstractEngine.prototype.tick = function() {
    this.prepareFrame();
    this.update();
    }
// Ok, we're in trouble. The error message is output to the console and I don't understand why... The prepareFrame() and update() methods are defined right afterwards:
    AbstractEngine.prototype.update = function() {
    console.log('updating!');
    }
    AbstractEngine.prototype.prepareFrame = function() {
    console.log('preparing frame');
    }
// I read my code twice, but didn't find beginner's mistakes like typo or whatever. But well, cosnider I'm a beginner

您需要将initLoop的定义更改为以下内容:

AbstractEngine.prototype.initLoop = function() {
    var that = this;
    setInterval(function () {
        that.tick();
    }, 1000 / 30);
}

这是因为this的解析延迟到执行时间,并且当执行间隔时,this指向window,而不是您的AbstractEngine实例。

通过在匿名函数中封装对tick的调用,我们创建了一个闭包,允许我们捕获that(我们将其设置为this)。通过在实例 that(即旧的 this)上调用方法 tick,我们可以恢复"this"的值)。

This:

setInterval(this.tick, 1000 / 30);
应:

var that = this;
setInterval(function () { that.tick(); }, 1000 / 30);

或交替:

setInterval(this.tick.bind(this), 1000 / 30);

说明:当您简单地传递this.tick时,这与执行以下操作相同:

var temp = this.tick;
setInterval(temp, 1000 / 30);

但是现在,当temp被调用时,JavaScript不知道this指针应该是什么;该信息丢失了,它最终被绑定到全局对象(window),或者在严格模式下绑定到null

因此,您需要以某种方式确保this.tick作为具有适当this指针的方法调用。有两种方法可以做到这一点:

  1. 通过将其封装在捕获var that = this的闭包中,您可以正确地将that.tick作为原始this指针的方法调用。
  2. 或者通过bind()this.tick函数调用到this,您可以确保每次都使用适当的this作为方法调用它:换句话说,您甚至可以执行var temp = this.tick.bind(this)setInterval(temp, 1000 / 30)

请注意,bind在较旧的浏览器中不可用(特别是IE <= 8和迄今为止包括5.1在内的所有safari),在这种情况下,您需要像es5-shim这样的东西。