2011-09-23 39 views
0

我已經寫了一個跳棋遊戲模型,其中包含一個包含一堆Piece對象的Board對象。 Piece對象有一個事件(pieceMoved),每次移動它們時都會觸發它們。將方法添加到Javascript中的對象實例並使用其中的'this'關鍵字

我正在使用EaselJS在canvas元素中呈現此遊戲模型。

我做的第一件事就是創建一個easeljs形狀對象來以圖形方式表示每件作品。

我希望處理件的相應形狀對象上的pieceMoved事件,以便我可以更新形狀位置。

,我創建的形狀和分配事件處理程序的代碼看起來是這樣的 -

for (x=0;x<=(board_.getColCount()-1);x++) { 
for (y=0;y<=(board_.getRowCount()-1);y++) { 

var piece = board_.getPieceAt(x, y); 

    if (!piece) continue; 

    var circ = new Shape(); 

    circ.eventHandler = function(pieceObj) { 
     this.x = pieceObj.x*squareSize; 
     this.y = pieceObj.y*squareSize; 
    } 

    piece.addEventHandler(circ.eventHandler); 

    .... 

的問題是,在事件處理程序內的「這個」關鍵詞並不是指正確的事情。我也試過以下 -

piece.addEventHandler(function(px) { return circ.eventHandler; }); 

但是,'this'指的是錯誤的對象。

做這種事情的正確方法是什麼?

回答

1

在事件處理程序,this指物體解僱了這個事件。有辦法繞過它,但我的理念是,你應該擁抱公約而不是與之抗爭。所以,僅僅從事件處理程序分離的方法:

piece.addEventHandler (function (e) { 
    circ.eventHandler(e); 
}); 

在你的情況,因爲它看起來像你有循環問題,創建一個處理程序工廠:

function getHandler (circ) { 
    return function(e) { 
     circ.eventHandler(e); 
    }; 
} 
for (var i = 0; i < circles.length; i++) { 
    piece.addEventHandler(getHandler(circles[i])); 
} 

編輯:美化它Array.forEach()。我猜,circles不是數組,所以你可能不得不使用.call()

[].forEach.call(circles, function(circ) { 
    piece.addEventHandler(function(e) { 
     circ.eventHandler(e); 
    }); 
}); 
+0

工廠選項是目前爲止唯一的工作。讓我畏縮了這麼多簡單的代碼。我能做些什麼來使它更漂亮? – NoPyGod

+0

@NoPyGod - 我已經添加了對美化我的答案的嘗試。請注意,對於IE8及更早版本,您需要[自己添加'Array.forEach()'](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility) – gilly3

+0

哎呦,我只是注意到你的編輯。 'Array.forEach()'在這裏沒有幫助。看起來我混淆了你正在迭代的項目。好吧。 – gilly3

0
piece.addEventHandler(function(px) { 
    circ.eventHandler(px); 
}); 

當您直接傳遞函數時,函數會丟失它們的上下文。這是因爲它是添加上下文的調用的點語法。所以當你簡單地傳遞一個對該函數的引用時,它會被直接調用,並且你失去了上下文。

因此,對於依賴於上下文的回調來說,傳遞匿名函數作爲回調通常是明智的,然後在內部做任何你需要做的事情。

另外,如果你要編輯的回調是如何調用你可以這樣做:

// event happened invoke handler! 
myEventHandler.call(this) 

將與你在哪裏(就好說了,你的作品調用它的上下文中執行的函數對象isntance)。

+0

剛剛嘗試過,它不起作用。因爲我發佈的代碼是循環運行的,並且棋盤上的每個棋子都重新創建了循環對象,所以'this'變量最後指的是創建的最後一個循環。 – NoPyGod

+0

那是一個完全不同的問題:)在這種情況下,如果你可以控制如何調用回調,然後嘗試我的其他建議。 –

+0

其他建議不可行,因爲我需要Circle對象作爲上下文,而不是Piece對象。 Piece對象不知道Circle對象,它只知道circle對象上的事件處理函數。 – NoPyGod

0

使用try bind(無參數):

piece.addEventHandler(circ.eventHandler.bind(circ)); 

或使用匿名功能,因爲這是一個封閉的問題:

piece.addEventHandler((function(circ) { 
    return function() { 
     circ.eventHandler.apply(circ, arguments); 
    }; 
})(circ)); 
1

嘗試移動代碼來創建圓形狀如一個方法,

function addShape(piece) { 
    var circ = new Shape(); 

    piece.addEventHandler(function (pieceObj) { 
     circ.x = pieceObj.x * squareSize; 
     circ.y = pieceObj.y * squareSize; 
    }); 

    return circ; 
} 

這將使環的樣子,

for (x = 0; x <= (board_.getColCount() - 1); x++) { 
    for (y = 0; y <= (board_.getRowCount() - 1); y++) { 
     var piece = board_.getPieceAt(x, y); 
     if (!piece) continue; 

     var circ = addShape(piece); 

     ... 
    } 
} 

我知道這並不實際工作中使用,但是,在這種情況下,它使代碼更復雜,你真的不需要它。

0

您必須簡單地作出關閉:

var that = this; 
circ.eventHandler = function(pieceObj) { 
    that.x = pieceObj.x*squareSize; // we will "remember" the correct scope now! 
    that.y = pieceObj.y*squareSize; 
} 

由於在不同的範圍比創建它的範圍功能火災,它會很困惑,在某種程度上。您需要通過關閉變量來設置它。你可以通過在你的函數之外引用它來引用它,然後在函數中使用該引用。這將允許該功能始終使用正確的「this」。

相關問題