2009-10-29 72 views
0

我對基本javascript以外的任何東西都不是很滿意,所以請原諒簡單的問題。Javascript - 從函數的局部範圍內獲取變量

我正在使用jsDraw2D庫。這圖書館,看起來像下面這樣的圖形對象:

function jsGraphics(canvasDivElement) { 
    var canvasDiv; 
    this.drawLine = drawLine; 
    function drawLine(point1, point2) { 
    // do things with canvasDiv 
    } 
} 

你使用這樣的:

var gr = new jsGraphics(document.getElementById('canvas')) 
gr.drawLine(new jsPoint(0,0), new jsPoint(10,10)) 

我想一個函數添加到jsGraphics,這樣我可以調用

gr.getCanvasElement() 

有沒有辦法做到這一點,而無需編輯庫本身?

我已經試過

jsGraphics.prototype.getCanvasElement = function() { return canvasDiv } 

但這似乎並沒有工作。我有一種直覺的感覺,即它與新關鍵字有關的東西,但是如果你能解釋爲什麼它確實不會有幫助。

+0

你是否像這樣將'document.getElementById('canvas')'傳遞給'jsGraphics'?如果您可以調用'document.getElementById('canvas')'來獲得'canvasDiv'所具有的同樣的功能。 –

+0

那麼我想要的不是canvasDiv,而是它的寬度/高度,它將用於我打算添加的一些簡化的外觀方法。但是頁面本身會有許多jsGraphics對象,我需要依次處理每個對象。 –

回答

3

您不能僅僅到達canvasDiv元素,因爲如果它從未在構造函數中使用this關鍵字指定給該對象,則該對象的引用將存在於由構造函數本身創建的閉包中。

但是你可以用一個新的構造函數的構造函數,然後設置原型等於:

function myJsGraphics(canvasDivElement) { 
    this.canvasDiv = canvasDivElement; 
    jsGraphics.call(this, cavasDivElement); 
} 

myJsGraphics.prototype = jsGraphics.prototype; 

現在,你應該能夠使用新的構造函數訪問元素:

var obj = new myJsGraphics(document.getElementById('blah-elem')); 
elem = obj.canvasDiv; 

的如果你不習慣它,整個封閉的事情有點奇怪,但要點是在某個範圍內定義但在其他地方可用的函數可以指代它們在任何時候被定義的範圍內的變量。最簡單的例子是,當你有一個返回函數的函數:

function makeIncrementer(start) { 
    return function() { return start++; }; 
} 

var inc = makeIncrementer(0); 
var inc2 = makeIncrementer(0); 
inc(); // => 0 
inc(); // => 1 
inc(); // => 2 
inc2(); // => 0 

,提及「開始」變量「關閉了」的時候,功能從makeIncrementer函數返回。它不能直接訪問。同樣的事情發生在對象的構造函數中,其中局部變量被「關閉」到對象的成員函數中,並且它們充當私有變量。除非在構造函數中定義了私有成員的方法或變量引用,否則您將無法訪問它。

+3

jsGraphics.call(this);應該是jsGraphics.call(this,canvasDivElement); – Chii

+0

感謝您指出,我做出了改變。 –

4

不是,這不是使用正常的基於JavaScript原型的繼承,而是將一個單獨的drawLine函數添加到jsGraphics的每個實例,每個實例都在其自己的canvasDiv變量周圍具有閉包。

一旦function jsGraphics() {已關閉}根本沒有其他方法可以訪問canvasDiv變量,除非其中一個函數提供對其的訪問。這通常是刻意製作私有變量,明確阻止你獲得canvasDiv。

+0

真的嗎?我認爲任何事情都可以在JavaScript中...從技術上講,我想把它看作是一個內部使用的保護變量,我將在未來添加一些方法,如果這使得它更容易。 –

+1

是的,我喜歡使用調試友好的Python方法,你可以將它設置爲'this._canvasDiv',並且使用變量開頭的下劃線的任何人都會受到傷害,除非它們是成員函數(或者他們真的知道它們是什麼正在做)。但是,這將需要您更改構造函數。 – bobince

2

這種「私人狀態」技術在過去幾年越來越習慣了。就我個人而言,當試圖從控制檯快速調試某些內容或重寫第三方庫中的行爲時,我發現它有着奇怪的限制。這是我認爲的幾次之一「該死的,爲什麼我不能用這種語言來做這件事」。當我真的需要快速調試「私有變量」時,我在Firefox 2中利用了this bug,效果很好。

我很想知道別人什麼時候使用這個成語,或者當他們避開它。 (@bobince我在看你)。

無論如何@bobince已經很好的回答了你的問題(簡而言之:不,你不能訪問你所在範圍的canvasDiv變量)。

但是,您可以做的一件事是在黑客或編輯第三方庫之間進行權衡(我總是爲黑客而努力):您可以增加對象以容納您知道的參考稍後需要。

哈克1:如果你控制實例自己的對象:

var canvas = document.getElementById('canvas'); 
var gr = new jsGraphics(canvas); 
gr._canvasDiv = canvas; // Augment because we'll need this later 

// Sometime later... 

gr._canvasDiv; // do something with the element 

如果庫支持一些概念類似於析構函數(頁面什麼的卸載解僱),一定要空出來或刪除其中的屬性也避免IE內存泄漏:

delete gr._canvasDiv; 

哈克2:只是包括庫後覆蓋的構造:

// run after including the library, and before 
// any code that instantiates jsGraphics objects 
jsGraphics = (function(fn) { 
    return function(canvas) { 
     this._canvasDiv = canvas; 
     return fn.apply(this, arguments) 
    } 
}(jsGraphics)) 

然後訪問元素(現在公開)爲gr._canvasDiv。關於在頁面卸載時刪除它的注意事項也適用。