2013-04-28 71 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

相关问题