2011-10-10 63 views
1

我在JavaScript中使用了一些關於OOP的教程。它似乎進展順利,直到我遇到以下...訪問實例方法時發生JavaScript OO問題

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

好的。我正在使用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 

回答

1

此:

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),在這種情況下,你需要像es5-shim可用。

+0

你的建議解決方案不會工作,因爲''這個''改變了你的匿名函數的意義,它傳遞給了'setInterval'。看到馬特的回答。 – JAAulde

+0

@JAAulde:????? – Domenic

+0

嘿,謝謝你的工作答覆和解釋。我現在要消化這些信息;)謝謝! – Jem

4

您需要更改的initLoop定義爲以下:

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

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

這是因爲this分辨率被延遲,直到執行時間和執行時間間隔時,this指向window,而不是AbstractEngine的實例。

通過在匿名函數中將呼叫打包爲tick,我們創建了一個閉包,它允許我們捕獲that(我們設置爲this)。通過調用方法tick實例即(這是這個),我們可以恢復「this」的值)。

+1

我的答案都是草擬的,但你之前發帖甚至可以將其粘貼到答案框中。 :) – JAAulde

+0

嗯,這是它!恭喜,謝謝:) – Jem