web-dev-qa-db-ja.com

JavaScriptデザインパターン:モジュールパターンと公開モジュールパターンの違いは?

私はこの本を読んでいますLearning JavaScript Design Patterns最近。わかりませんが、モジュールパターンと公開モジュールパターンの違いです。それらは同じものだと思います。誰でも例を挙げることができますか?

54
Wayou

モジュールパターンを実装するには、少なくとも3つの異なる方法がありますが、明らかになっているモジュールパターンは、正式な名前を持つ唯一のモジュールパターンの子孫です。

基本モジュールパターン

モジュールパターンは次の条件を満たす必要があります。

  • 非公開メンバーは閉鎖中に住んでいます。
  • パブリックメンバーは、戻りオブジェクトで公開されます。

しかし、この定義には多くのあいまいさがあります。あいまいさを異なる方法で解決することにより、モジュールパターンのバリエーションを取得できます。

明らかなモジュールパターン

Revealing Moduleパターンは、最も有名で最も人気のあるModule Patternバリアントです。次のような他の選択肢よりも多くの利点があります。

  • 関数本体を変更せずにパブリック関数の名前を変更します。
  • 関数の本体を変更せずに、単一行を変更することにより、メンバーをパブリックからプライベート、またはその逆に変更します。

RMPは、元の条件に加えて3つの追加条件を満たします。

  • すべてのメンバーは、パブリックまたはプライベートにかかわらず、クロージャーで定義されます。
  • 戻りオブジェクトは、関数定義のないオブジェクトリテラルです。右辺の式はすべてクロージャー変数です
  • すべての参照は、戻りオブジェクトではなく、クロージャー変数を介して行われます。

次の例は、その使用方法を示しています

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

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

オブジェクトリテラルを使用したモジュールパターン

これはおそらく、モジュールパターンの最も古いバリアントです。 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!");}
  }
})();

Unlke RMPは、nameおよびsayHelloをプライベートにするために、さまざまな関数本体定義でnameおよびsayHelloを指す参照もする必要があることに注意してください。変更される.

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

戻りオブジェクトスタブを使用したモジュールパターン

この亜種にも正式な名前はありません。

オリジナルに加えて、次の条件を満たす。

  • 空の戻りオブジェクトスタブが最初に定義されます。
  • プライベートメンバーはクロージャーで定義されます。
  • パブリックメンバーはスタブのメンバーとして定義されます
  • パブリックメンバーへの参照は、スタブオブジェクトを介して行われます

古い例を使用すると、パブリックメンバーがスタブオブジェクトに直接追加されていることがわかります。

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

以前のように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;
})();

概要

Revealingモジュールパターンとモジュールパターンの他のバリエーションの違いは、主にパブリックメンバーの参照方法にあります。その結果、RMPの使用と変更がはるかに簡単になり、人気が高まっています。しかし、これらの利点には大きなコストがかかります(私の意見では)、Addy Osmaniが Revealing Module Pattern の投稿で言及しています。

このパターンの欠点は、プライベート関数がパブリック関数を参照する場合、パッチが必要な場合にパブリック関数をオーバーライドできないことです。これは、プライベート関数は引き続きプライベート実装を参照し、パターンはパブリックメンバーには適用されず、関数にのみ適用されるためです。

プライベート変数を参照するパブリックオブジェクトメンバーも、上記のパッチなしルールの注意事項に従います。

この結果、Reveinging Moduleパターンで作成されたモジュールは、元のModuleパターンで作成されたモジュールよりも壊れやすい可能性があるため、使用中は注意が必要です。

そして、私はいくつかの otherposts で話しました。

102
I-Lin Kuo

簡単な答え、モジュールパターンでは、オブジェクトを返す際の関数を定義します。

Revealing Moduleパターンでは、クロージャ領域で関数を定義し、オブジェクトを返すときにのみ変数名を使用します。

これを行うと、コードが簡素化され、他の多くの利点があります

2
Sumer

一番上のコメントの回答に基づいて何かをしようとしてください。 thisを渡してプライベート関数を呼び出すとより安全になる可能性があるため、プライベート関数は-でパブリック関数を参照できますthis変数。

次のコードを使用して、公開モジュールパターンを作成しました。

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!

ご覧のとおり、パブリックメンバーをオーバーライドできます。

0
Semooze