JavaScript设计模式:模块模式和揭示模块模式之间的区别?

Way*_*you 54 javascript design-patterns module-pattern revealing-module-pattern

我最近在阅读" 学习JavaScript设计模式 "一书.我没有得到的是模块模式和揭示模块模式之间的区别.我觉得他们是一回事.有谁可以举个例子?

I-L*_*Kuo 103

实现模块模式至少有三种不同的方法,但Revealing Module Pattern是唯一具有正式名称的Module Pattern后代.

基本模块模式

模块模式必须满足以下条件:

  • 私人成员住在关闭.
  • 公共成员在返回对象中公开.

但是这个定义中存在很多含糊之处.通过不同地解决歧义,您可以获得模块模式的变体.

揭示模块模式

Revealing Module Pattern是最着名和最受欢迎的Module Pattern变体.与其他替代方案相比,它具有许多优点,例如

  • 重命名公共函数而不更改函数体.
  • 通过修改单行来将成员从公共变为私有,反之亦然,而无需更改函数体.

除了原始版本之外,RMP还满足三个附加条件:

  • 所有成员,无论是公共成员还是私人成员,都在关闭中定义.
  • 返回对象是没有函数定义的对象文字.所有右侧表达式都是闭包变量
  • 所有引用都是通过闭包变量,而不是返回对象.

以下示例显示了它的使用方式

var welcomeModule = (function(){
  var name = "John";
  var hello = function(){ console.log("Hello, " + name + "!");}
  var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return {
    name: name,
    sayHello: hello,
    sayWelcome: welcome
  }
})();
Run Code Online (Sandbox Code Playgroud)

如果你想使namesayHello私有的,你只需要在返回的对象注释掉适当的行.

var welcomeModule = (function(){
  var name = "John";
  var hello = function(){ console.log("Hello, " + name + "!");}
  var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return {
    //name: name,
    //sayHello: hello,
    sayWelcome: welcome
  }
})();
Run Code Online (Sandbox Code Playgroud)

具有对象文字的模块模式

这可能是模块模式的最早变体.与RMP不同,这种变体没有性感的官方名称.

除原始版本外,它还满足以下条件:

  • 私有成员在闭包中定义.
  • 公共成员在返回对象文字中定义.
  • this只要有可能,就可以通过参考公众成员.

在下面的示例中,您可以看到,与RMP相比,函数定义实际上是如何在返回对象文字中,并且成员的引用是由限定的this.

var welcomeModule = (function(){
  return {
    name: "John",
    sayHello: function(){ console.log("Hello, " + this.name + "!");}
    sayWelcome: function() { console.log( this.hello() + " Welcome to StackOverflow!");}
  }
})();
Run Code Online (Sandbox Code Playgroud)

请注意,为了制作namesayHello私有,必须更改指向namesayHello在各种函数体定义中的引用.

var welcomeModule = (function(){
  var name: "John";
  var sayHello = function(){ console.log("Hello, " + name + "!");};
  return {
    //name: "John",
    //sayHello: function(){ console.log("Hello, " + this.name + "!");}
    sayWelcome: function() { console.log( hello() + " Welcome to StackOverflow!");}
  }
})();
Run Code Online (Sandbox Code Playgroud)

具有返回对象存根的模块模式

此变体也没有正式名称.

除原始版本外,它还满足以下条件:

  • 在开头定义一个空的返回对象存根.
  • 私有成员在闭包中定义.
  • 公共成员被定义为存根的成员
  • 公共成员的引用是通过存根对象

使用我们的旧示例,您可以看到公共成员直接添加到存根对象.

var welcomeModule = (function(){
  var stub = {};
  stub.name = "John";
  stub.sayHello = function(){ console.log("Hello, " + stub.name + "!");}
  stub.sayWelcome = function() { console.log( stub.hello() + " Welcome to StackOverflow!");}
  return stub;
})();
Run Code Online (Sandbox Code Playgroud)

如果您想像以前一样制作namesayHello私有,则必须更改对现在私有成员的引用.

var welcomeModule = (function(){
  var stub = {};
  var name = "John";
  var sayHello = function(){ console.log("Hello, " + name + "!");}

  stub.sayWelcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return stub;
})();
Run Code Online (Sandbox Code Playgroud)

摘要

揭示模块模式与模块模式的其他变体之间的差异主要在于如何引用公共成员.因此,RMP更易于使用和修改,这也是其受欢迎程度的原因.然而,这些优势成本很高(在我看来),Addy Osmani在他的关于揭示模块模式的帖子中暗示,

这种模式的缺点是,如果私有函数引用公共函数,则如果需要补丁,则不能覆盖该公共函数.这是因为私有函数将继续引用私有实现,并且该模式不适用于公共成员,仅适用于函数.

引用私有变量的公共对象成员也受上面的无补丁规则说明的约束.

因此,使用Revealing Module模式创建的模块可能比使用原始模块模式创建的模块更脆弱,因此在使用期间应该小心.

我在其他 一些帖子中谈过这个问题.

  • @ I-LinKuo在你的代码示例中有几个破坏的引用 - 例如sayHello vs hello (4认同)
  • 很棒的答案.十分感谢!现在事情很清楚了. (3认同)

Sum*_*mer 7

简短的回答,在模块模式中,我们在返回对象中定义函数。

在 Revealing Module 模式中,我们在闭包区域定义函数,并且只在返回对象中使用变量名。

这样做可以简化代码并具有许多其他优点