Ошибка OO JavaScript при доступе к методам экземпляра - PullRequest
1 голос
/ 10 октября 2011

Я использовал несколько руководств по ООП в JavaScript. Казалось, все прошло хорошо, пока я не встретил следующее ...

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

Ответы [ 2 ]

4 голосов
/ 10 октября 2011

Вам необходимо изменить определение initLoop на следующее:

AbstractEngine.prototype.initLoop = function() {
    var that = this;

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

Это связано с тем, что разрешение this задерживается до времени выполнения, а при выполнении интервала this указывает на window, а не на ваш экземпляр AbstractEngine.

Обернув вызов к tick в анонимную функцию, мы создаем замыкание, которое позволяет нам захватить that (который мы установили на this). Вызвав метод tick для экземпляра (который является old this), мы можем восстановить значение "this").

1 голос
/ 10 октября 2011

Это:

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 и всех Safaris до 5.1 включительно), в этом случае вам понадобится что-то вроде <a href="https://github.com/kriskowal/es5-shim" rel="nofollow"> ES5-регулировочная шайба .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...