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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22906662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 23:59:59  来源:igfitidea点击:

JavaScript design pattern: difference between module pattern and revealing module pattern?

javascriptdesign-patternsmodule-patternrevealing-module-pattern

提问by Wayou

I'm reading the book Learning JavaScript Design Patternsrecently. What I don't get is the difference between module pattern and revealing module pattern. I feel they are the same thing. Anyone can give an example?

我最近正在阅读《学习 JavaScript 设计模式》这本书。我不明白的是模块模式和揭示模块模式之间的区别。我觉得他们是同一个东西。任何人都可以举个例子吗?

回答by I-Lin Kuo

There are at least three different ways to implement the Module Pattern, but the Revealing Module Pattern is the only Module Pattern descendant that has an official name.

至少有三种不同的方式来实现模块模式,但揭示模块模式是唯一具有正式名称的模块模式后代。

The Basic Module Pattern

基本模块模式

The Module Pattern must satisfy the following:

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

  • Private members live in the closure.
  • Public members are exposed in the return object.
  • 私人成员住在关闭。
  • 公共成员在返回对象中公开。

But there's a lot of ambiguity in this definition. By resolving the ambiguity differently, you get variants of the Module Pattern.

但是这个定义有很多歧义。通过以不同方式解决歧义,您可以获得模块模式的变体。

The Revealing Module Pattern

揭示模块模式

The Revealing Module Pattern is the most famous and most popular of the Module Pattern variants. It has a number of advantages over the other alternatives, such as

揭示模块模式是最著名和最受欢迎的模块模式变体。与其他替代方案相比,它具有许多优点,例如

  • Rename public functions without changing function body.
  • Change members from public to private or vice versa by modifying a single line, without changing the function body.
  • 重命名公共函数而不更改函数体。
  • 通过修改单行将成员从公共更改为私有,反之亦然,而无需更改函数主体。

The RMP satisfies three additional conditions in addition to those in the original:

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

  • All members, whether public or private, are defined in the closure.
  • The return object is an object literal with no function definitions. All right hand side expressions are closure variables
  • All references are via the closure variables, not the return object.
  • 所有成员,无论是公共的还是私有的,都在闭包中定义。
  • 返回对象是一个没有函数定义的对象字面量。所有右手边的表达式都是闭包变量
  • 所有引用都是通过闭包变量,而不是返回对象。

The following example shows how it's used

下面的例子展示了它是如何使用的

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
  }
})();

If you wanted to make nameand sayHelloprivate, you just need to comment out the appropriate lines in the return object.

如果你想制作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
  }
})();

The Module Pattern with Object Literal

带有对象字面量的模块模式

This is probably the oldest variant of the Module Pattern. Unlike RMP, there's no sexy official name for this variant.

这可能是模块模式最古老的变体。与 RMP 不同的是,这个变体没有性感的官方名称。

It satisfies the following conditions, in addition to the original:

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

  • Private members are defined in the closure.
  • Public members are defined in the return object literal.
  • References to public members are via this, whenever possible.
  • 私有成员在闭包中定义。
  • 公共成员在返回对象文字中定义。
  • this只要可能,对公共成员的引用都是通过。

In the following example, you can see how, in contrast to RMP, the function definitions are actually in the return object literal, and references to members are qualified by 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!");}
  }
})();

Note that unlke RMP, in order to make nameand sayHelloprivate, the references pointing to nameand sayHelloin the various function body definitions also have to be changed.

注意unlke RMP,为了makenamesayHelloprivate,指向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!");}
  }
})();

The Module Pattern with Return Object Stub

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

This variant also has no official name.

该变体也没有正式名称。

It satisfies the following conditions, in addition to the original:

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

  • An empty return object stub is defined at the beginning.
  • Private members are defined in the closure.
  • Public members are defined as members of the stub
  • References to public members are via the stub object
  • 在开头定义了一个空的返回对象存根。
  • 私有成员在闭包中定义。
  • 公共成员被定义为存根的成员
  • 对公共成员的引用是通过存根对象

Using our old example, you can see that public members are directly added to the stub object.

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

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;
})();

If you want to make nameand sayHelloprivate as before, the references to the now-private members have to be changed.

如果您想像以前一样创建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;
})();

Summary

概括

The differences between the Revealing Module Pattern and the other variants of the Module Pattern is primarily in how public members are referenced. As a result, RMP is much easier to use and modify, which accounts for its popularity. However, these advantages come at a great cost (in my opinion), which Addy Osmani alludes to in his post on the Revealing Module Pattern,

揭示模块模式和模块模式的其他变体之间的区别主要在于如何引用公共成员。因此,RMP 更易于使用和修改,这也是其受欢迎的原因。然而,这些优势付出了巨大的代价(在我看来),Addy Osmani 在他关于揭示模块模式的帖子中提到了这一点,

A disadvantage of this pattern is that if a private function refers to a public function, that public function can't be overridden if a patch is necessary. This is because the private function will continue to refer to the private implementation and the pattern doesn't apply to public members, only to functions.

Public object members which refer to private variables are also subject to the no-patch rule notes above.

As a result of this, modules created with the Revealing Module pattern may be more fragile than those created with the original Module pattern, so care should be taken during usage.

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

引用私有变量的公共对象成员也受上述无补丁规则注释的约束。

因此,使用揭示模块模式创建的模块可能比使用原始模块模式创建的模块更脆弱,因此在使用过程中应小心。

and which I've talked about in some otherposts.

我在其他一些帖子中谈到过。

回答by Sumer

Short answer, In Module pattern we define functions in returning object.

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

In Revealing Module pattern, we define functions in closure area and only use variable names in returning object.

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

Doing this simplifies the code and has lot of other advantages

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

回答by Semooze

Just try to do something based on top comment answer. May be it is safer if call private function by passing thisto it, so private function could reference public function with thisvariable.

尝试根据热门评论答案做一些事情。如果通过将this传递给私有函数来调用私有函数可能更安全,因此私有函数可以使用变量引用公共函数。

I created a revealing module pattern with following code.

我使用以下代码创建了一个揭示模块模式。

var HTMLChanger = (function () {
    var privateFunc = function () {
        this.sayHello();
    }

    var hello = function () {
        console.log('say Hello');
    }
    var callPrivate = function () {
        privateFunc.call(this);
    }


    return {
        sayHello: hello,
        callPrivate: callPrivate
    };
})();

HTMLChanger.callPrivate();
//say Hello

HTMLChanger.sayHello = function() { console.log('say Hi!') };

HTMLChanger.callPrivate();
//say Hi!

As you can see we can override public member.

如您所见,我们可以覆盖公共成员。