2015-06-12 94 views
0

我試圖以面向對象的方式組織我的代碼(如MDN中所述)。然而在我的情況下,這個指的是窗口對象。因爲我得到的錯誤JavaScript範圍問題(this)

Uncaught TypeError: Cannot read property 'render' of undefined

this.renderer.render(this.stage);

爲什麼這是指當它不會對MDN窗口對象?

var GAME = GAME || {}; 

GAME.Application = function() { 
    this.renderer = PIXI.autoDetectRenderer(800, 600,{backgroundColor : 0x1099bb}); 
    document.getElementById("game").appendChild(this.renderer.view); 
    this.stage = new PIXI.Container(); 
    requestAnimationFrame(this.render); 
} 

GAME.Application.prototype.render = function() { 
    this.renderer.render(this.stage); 
} 

var app = new GAME.Application(); 

回答

1

講起this,上下文和功能

去想它的一個好方法,就是this指的是調用它的方法的.左側的對象。

var someObj = { 
    name:'someObj', 
    sayName: function(){ 
     console.log(this.name); 
    } 
}; 

someObj.sayName(); // prints someObj 

不是對象的方法的函數被綁定到窗口對象。

window.name = 'window'; 
function sayName(){ 
    console.log(this.name); 
} 

sayName(); //prints window 

以上相當於

window.sayName(); // window is on the left of the dot, so it is `this` 

當傳遞的對象的方法作爲參數,或將其分配給一個變量,它失去它的原始上下文。下面,someObj的sayName方法會丟失someObj作爲上下文,並獲得一些其他對象。

var someOtherObj = { 
    name:'someOtherObj' 
}; 

someOtherObj.sayName = someObj.sayName; 

someOtherObj.sayName(); // prints someOtherObj 

要解決它,你可以一個上下文綁定到一個功能

var yetAnotherObj = { 
    name: 'yetAnotherObj' 
}; 

var sayYetAnotherObj = sayName.bind(yetAnotherObj); 

sayYetAnotherObj(); // prints yetAnotherObj 

或者通過調用該方法的對象本身

var OneLastObj = function(){ 
    var self = this; 
    this.someValue = aFunctionTakingAcallback(function(){ 
     return self.doSomeStuff(); 
    }); 
} 

東西對一個匿名函數請記住,當傳遞函數作爲參數時,您傳遞的是函數的引用。函數本身並不綁定到它可能是一個方法的對象。

4

您需要綁定您的render函數。這可能是最直接的解決方案。

requestAnimationFrame(this.render.bind(this)); 

或者相反,你可以做

var context = this; 
requestAnimationFrame(function() { 
    context.render(); 
}); 

或者你可以避免創建自由變量和使用IIFE

requestAnimationFrame((function(context) { 
    context.render(); 
})(this))); 

或者,如果你使用ES6,你可以使用箭頭功能

requestAnimationFrame(() => this.render()); 

另一種簡單的改進,你可以讓正在通過渲染元素到您的應用程序構造

function Application(elem) { 
    this.renderer = ... 
    elem.appendChild(this.renderer.view); 
} 

new Application(document.getElementById("game"));