2013-04-28 72 views
4

我正在嘗試在小項目中實現一些常見的JS概念 以更好地理解如何使用它們。將模塊模式與閉包結合的最佳方式

我一直在做一個簡單的遊戲,試圖 理解和使用模塊模式和關閉。 我使用Stoyan Stefanov的'模式' 書中的模塊模式。

我很努力去理解如何最好地將模塊和 關閉。

我想知道如果我以 明智的方式組織下面的代碼?如果是這樣,我的問題是: 修改代碼的最佳方法是什麼,以便在$(function(){})我有 訪問update()函數?

MYAPP.utilities = (function() { 

    return { 
     fn1: function(lives) { 
      //do stuff 
     } 
    } 
})(); 

MYAPP.game = (function() { 

    //dependencies 
    utils = MYAPP.utilities 

    return { 
     startGame: function() { 

      //initialisation code 
      //game state, stored in closure 
      var lives = 3; 
      var victoryPoints = 0; 

      function update(){ 
       utils.fn1(lives); 
       //do other stuff 
      } 

     } 
    } 
})(); 

$(function(){ 
    MYAPP.game.startGame(); 

    //Want to do this, but it won't work 
    //because I don't have access to update 

    $('#button').on('click',MYAPP.game.update) 

}); 

我已經想出了幾個這將工作的選擇,但我 想知道,如果他們是很好的做法,最好的選擇 什麼。

選項:

(1)綁定$('#button').on('click', ...)作爲 startGame初始化代碼的一部分。

(2)指定update()函數的變量, 回報從startGame功能這個變量,所以在 $(function(){})我們能有 updatefn = MYAPP.game.startGame();然後

(3)?有沒有更好的辦法?

非常感謝您的幫助,

羅賓

回答

4

首先,訪問該方式它必須在返回的對象公開update功能。

return { 
    update: function() { 
     [...] 
    }, 
    startGame: function() { 
     [...] 
     this.update(); 
    } 
} 

調用obj.method()自動將此method調用objthis參考。也就是說,在startGame方法調用中調用MYAPP.game.startGame()設置thisMYAPP.game。有關此行爲的更多詳細信息here

你也想給lives變量移動到一個共同的範圍是由兩個startGameupdate方法訪問,這是完全封閉是什麼:

MYAPP.game = (function() { 

    [...] 
    var lives; //private/privileged var inside the closure, only accessible by 
       //the returned object's function properties 

    return { 
     update: function() { 
      utils.fn1(lives); 
     }, 
     startGame: function() { 
      [...] 
      lives = 3; //sets the closure scope's lives variable 
      [...] 
      this.update(); 
     } 
    } 
})(); 

Fiddle

在這如果您想要更改它,您將需要一些方法來設置lives變量。另一種方法是使lives變量公開,並將其作爲返回對象的屬性,並通過方法內的this.lives來訪問它。

注:如果你簡單地傳遞作爲存儲作爲返回對象的屬性的函數對象的引用:

$('#button').on('click', MYAPP.game.update); 

單擊處理程序內的this引用將MYAPP.game爲已經傳遞的函數引用將直接從jQuery核心調用,而不是作爲對象的成員函數調用 - 在這種情況下,this將指向#button元素,因爲jQuery事件處理程序將this引用到觸發處理程序的元素,如您所見here

爲了補救,您可以使用Function.bind()

$('#button').on('click', MYAPP.game.update.bind(MYAPP.game)); 

還是老功能的包裝伎倆:

$('#button').on('click', function() { 
    MYAPP.game.update(); //called as method of an obj, sets `this` to MYAPP.game 
}); 

this關鍵字的update方法中用到這一點很重要。

+0

謝謝你明確的答案。 – RobinL 2013-04-28 08:19:28

1

你的代碼有幾個問題。首先,update()函數在您創建的對象外部不可見。要使其成爲game對象的一部分,它必須與startGame處於同一水平。

此外,如果您聲明var lives = 3它將是一個局部變量,它將不會在startGame()函數以及victoryPoints之外可見。這兩個變量必須以某種方式可見(通過閉包或作爲對象字段)。

最後,作爲事件偵聽器附加MYAPP.game.update將僅附加該函數,從而阻止您使用所有其他對象方法/函數。取決於你想要做什麼,你可能更喜歡通過像function() { MYAPP.game.update() }這樣的閉包。

你的代碼應該是這個樣子:

MYAPP.utilities = (function() { 

    return { 
     fn1: function(lives) { 
      console.log(lives); 
     } 
    } 
})(); 

MYAPP.game = (function() { 

    //dependencies 
    utils = MYAPP.utilities 

    var lives; 
    var victoryPoints; 

    return { 
     startGame: function() { 

      //initialisation code 
      //game state, stored in closure 
      lives = 3; 
      victoryPoints = 0; 
     }, 

     update: function() { 
      utils.fn1(lives); 
      //do other stuff 
     } 
    } 
})(); 

$(function(){ 
    MYAPP.game.startGame(); 

    //Want to do this, but it won't work 
    //because I don't have access to update 

    $('#button').on('click', MYAPP.game.update) 

}); 

DEMO on jsfiddle

+0

謝謝 - 這很有道理 – RobinL 2013-04-28 08:20:09

相關問題