2011-12-20 28 views
1

我是一種新的方式JavaScript的範圍,所以這是我的問題:逃生JavaScript事件範圍

"use strict"; 

function Explorer(xPos, yPos) { 

    // Inheritance 
    GraphicsEntity.call(this, { 
     x: xPos, 
     y: yPos, 
     width: 32, 
     height: 32 
    }); 

    // Local fields 
    var _texture = new Image(); 

    // Contruct 
    _texture.addEventListener("load", function() { 

     this.graphics.drawImage(_texture, 0, 0); 

    }, false); 

    _texture.src = "explorer.png"; 

} 

這會拋出異常:遺漏的類型錯誤:無法調用未定義

法「的drawImage」

我知道這是由於JavaScript範圍的方式,因爲'this'現在引用'_texture'字段。 正如你所看到的Explorer(某種類似玩家的對象)從GraphicsObject繼承而來,GraphicsObject又有一個屬性graphics(canvas元素的上下文)。

我已經找到一種方法來解決這個問題,但在我看來,這是一個有點髒之一:

"use strict"; 

function Explorer(xPos, yPos) { 

    // Inheritance 
    GraphicsEntity.call(this, { 
     x: xPos, 
     y: yPos, 
     width: 32, 
     height: 32 
    }); 

    // Local fields 
    var _texture = new Image(); 
    var _graphics = this.graphics; 

    // Contruct 
    _texture.addEventListener("load", function() { 

     _graphics.drawImage(_texture, 0, 0); 

    }, false); 

    _texture.src = "explorer.png"; 

} 

因此,作爲目前預計所有作品,圖像被整齊地畫在畫布上的元素。 唯一的問題是,我現在有另一個參考'圖形'我真的不想要。

所以我的問題是: 有沒有什麼辦法讓'this'引用Explorer對象,或者強制範圍改變?

回答

3

this對函數來說總是局部的,每次調用函數時都會對函數進行評估,這取決於函數的調用方式。在這種情況下,瀏覽器將this設置爲_texture指向的圖像對象。

由於正常的變量從外部範圍擡頭,你可以簡單地將舊this保存到某個變量:

function Explorer(xPos, yPos) { 
    var self = this; 

    // Inheritance 
    GraphicsEntity.call(this, { 
     x: xPos, 
     y: yPos, 
     width: 32, 
     height: 32 
    }); 

    // Local fields 
    var _texture = new Image(); 
    // Contruct 

    _texture.addEventListener("load", function() { 
     self.graphics.drawImage(_texture, 0, 0); 
    }, false); 

    _texture.src = "explorer.png"; 
} 
+0

+1 - 就是這樣 – 2011-12-20 16:19:09

+0

所以基本上和我修正它的方式一樣,但是使用對整個Object本身的引用?嗯......這可以工作。 – 2011-12-20 16:42:01

+0

@JonKoops最好只使用整個對象,它只是一個引用,所以它不會佔用更少或更多的內存(即使多個事物指向內存,對象在內存中仍然只有一種表示形式)。這樣,當你在回調中需要比'explorer.graphics'更多的東西時,你不需要重寫。 – Esailija 2011-12-20 16:48:31

2

您還沒有顯示的功能GraphicsEntity,但我敢肯定,這個問題是這樣的:

GraphicsEntity.call(this, { 

在你的函數Explorerthis將是全局對象(當然,除非Explorer也被稱爲與call),這是call的呼叫設置thisGraphicsEntity。這很可能就是你得到這個例外的原因。

另外,是GraphicsEntity一個對象,或功能?我問,因爲call預計功能call調用給定的函數,將第一個參數設置爲this值,隨後的參數作爲該函數的參數傳遞。

編輯

正如Esailija已經說過,this價值是它在你的函數的開頭是什麼在你的負載情況下的回調不同。將this的值保存到函數開頭的局部變量中,並在回調中使用

+0

'Explorer'使用像一個正常的對象,並且該似乎很好地工作。問題是Image.load事件中的範圍。 – 2011-12-20 16:29:53

1

一個可能的解決方案是使用一個包裝的功能,將創建你所需要的情況和捕獲您的國家。

如:

function draw(me) { 
    me.graphics.drawImage(_texture, 0, 0); 
} 

function wrapper(me) { 
    return function() { draw(me) }; 
} 

... 
_texture.addEventListener('load', wrapper(this)); 
... 

它比你的解決方案更簡潔一些?這是有爭議的,但你可以使它足夠通用,可以在其他情況下重用。

+0

這似乎工作,所以它保留在一個字段中的上下文,並返回它,以便以後可以使用。智能:) 我該如何去做這個'通用'? 不錯的解決方案,我真的很感謝你的幫助。 – 2011-12-20 16:34:23

+0

通過原型繼承,您可以使所有感興趣的對象具有'wrapper()'定義。你也可以添加第二個參數作爲函數本身(將wrapper方法從特定的方法實現中分離出來,就像'wrapper(me,f){return function(){f(me);};}')。這是否優於使用'self'方法是有爭議的,因爲它顯然比較慢,但它也更加靈活(您可能需要在包裝方法中進行額外的設置,以便共享)。 – lsoliveira 2011-12-20 16:47:08

+0

謝謝您的解釋,也許我會在將來使用這種方法:) – 2011-12-20 17:06:48

1

您還可以使用bind將上下文綁定到函數範圍

「use strict」;

功能資源管理器(XPOS,yPos){

// Inheritance 
GraphicsEntity.call(this, { 
    x: xPos, 
    y: yPos, 
    width: 32, 
    height: 32 
}); 

// Local fields 
var _texture = new Image(); 

// Contruct 
_texture.addEventListener("load", function() { 

    this.graphics.drawImage(_texture, 0, 0); 

}.bind(this), false); 

_texture.src = "explorer.png"; 

}