12

これはすでに何度も尋ねられている可能性があり、私は SO を検索しましたが、これまでに読んだすべての回答は、私が探しているものではありません。

私は、中程度のDOM要素の表示/非表示、いくつかのAJAX呼び出し、およびおそらく他の何かを含むWebサイトに取り組んでいます。したがって、2 つのメイン スクリプト ファイル (HTML5 ボイラープレート標準) を作成します。

plugins.js // third party plugins here
site.js // all my site specific code here

以前はオブジェクト リテラル デザイン パターンを使用していたので、site.js次のようなものです。

var site = {
  version: '0.1',
  init: function() {
    site.registerEvents();
  },
  registerEvents: function() {
    $('.back-to-top').on('click', site.scrollToTop);
  },
  scrollToTop: function() {
    $('body').animate({scrollTop: 0}, 400);
  }
};

$(function() {
  site.init();
});

これまでのところ非常に優れており、読みやすく、すべてのメソッドが公開されています (必要に応じて Chrome Dev Tools を介して直接テストできるため、これが気に入っています)。ただし、サイトの機能の一部をよりモジュール化されたスタイルに分離するつもりなので、上記のコードの下 (または別のファイル) に次のようなものを配置したいと考えています。

site.auth = {
  init: function() {
    site.auth.doms.loginButton.on('click', site.auth.events.onLoginButtonClicked);
  },
  doms: {
    loginButton: $('.login'),
    registerButton: $('.register')
  },
  events: {
    onLoginButtonClicked: function() {
    }
  },
  fbLogin: function() {
  }
};

site.dashboard = {
};

site.quiz = {
};

// more modules

ご覧のとおり、非常に読みやすいです。site.auth.doms.loginButtonただし、明らかな欠点が 1 つあります。それは、やのようなコードを書かなければならないことですsite.auth.events.onLoginButtonClicked。突然読みにくくなり、機能が複雑になるほど長くなるだけです。次に、モジュラー パターンを試しました。

var site = (function() {
  function init() {
    $('.back-to-top').on('click', scrollToTop);
    site.auth.init();
  }

  function scrollToTop() {
    $('body').animate({scrollTop: 0}, 400);
  }

  return {
    init: init
  }
})();

site.auth = (function() {
  var doms = {
    loginButton: $('.login'),
    registerButton: $('.register')
  };

  function init() {
    doms.loginButton.on('click', onLoginButtonClicked);
  }

  function onLoginButtonClicked() {

  }

  return {
    init: init
  }
})();

// more modules

ご覧のとおり、これらの長い名前はなくなりましたが、それらをすべて構築するには、site.init() 関数で他のすべてのモジュールを初期化する必要があるのではないでしょうか? 次に、他のモジュールからアクセスできるようにする必要がある関数を返すことを覚えておく必要があります。どちらも問題ありませんが、少し面倒ではありますが、全体として、モジュラー パターンを使用するより良いワークフローに取り組んでいますか?

4

1 に答える 1

16

もちろん、ここでの正解は「場合による」です。

サイトのすべてのセクションが 100% 公開されているため、すべてのデータとすべてのメソッドに完全に問題がない場合は、単一のリテラル (または複数のリテラル) を、必要に応じてネストされたオブジェクトと共に使用するだけで問題ありません。 1 つの巨大なコードのボールにならないようにします。

何らかの永続性を持つ(つまり、関数を実行するたびにリセットされない)任意の種類のプライベート状態が必要な場合は、公開モジュールが最適です。


はいえ、メソッドを持つことは、明らかにモジュールの要件ではありません.init
モジュールが自己完結型である場合は、公開したいものをエクスポートすることに集中してください。

この目的のために、後でチームが参照する可能性のあるコードを書いているときに、public_interfaceオブジェクトを作成してそれを返すことに気が付きます (返される匿名オブジェクトの名前付きバージョン)。

これの利点は、公開する必要があるものはすべてインターフェイスに追加する必要があるという理解を追加することを除いて、最小限です。

あなたが現在それを使用している方法:

var module = (function () { /* ... */ return {}; }());

module.submodule = (function () { /*...*/ return {}; }());

これはリテラルと同じくらい簡単にできるため、リテラルよりも良くも悪くもありません。

var module = {
    a : "",
    method : function () {},
    meta : { }
};

module.submodule = {
    a : "",
    method : function () {},
    meta : { }
};

自分に合わないものにぶつかるまでは、自分のニーズを満たすものに取り組んでください。

個人的には、通常、データのみのオブジェクトをリテラルとして構築します: config-objects、他の接続から入ってくるオブジェクトなど...

おそらく1つまたは2つのメソッドを必要とし、1つまたは2つのレベルの深さだけをネストすることで構築できる汚れのないオブジェクトは、文字通り構築することもできます(初期化を必要としない限り)。

// ex:
var rectangle = {
    width  : 12,
    height : 24,
    area : 0,
    perimeter : 0,
    init_area : function () { this.area = this.width * this.height; return this; }, // buh...
    init_perimeter : function () { this.perimeter = (this.width * 2) + (this.height * 2); return this; } // double-buh...
}.init_area().init_perimeter();

これらがいくつか必要な場合は、おそらくコンストラクターを作成します。
しかし、このようなユニークなものの1つだけが必要な場合は、次のようなことをするだけで頭痛の種が減るのではないでしょうか:

var rectangle = (function (width, height) {
    var public_interface = {
        width  : width,
        height : height,
        area   : width * height,
        perimeter : (2 * width) + (2 * height)
    };
    return public_interface;
}(12, 24));

より高度な計算が必要な場合は、余分な変数を非公開にして、内部から処理することができます。
オブジェクト内に機密データとそのデータを処理する関数が必要な場合は、アクセスを提供するのではなく、それらのプライベート関数を呼び出して結果を返すパブリック関数を使用できます。

また、コードをリファクタリングし、rectangleある時点で名前を変更することにした場合、参照している 3 つ以上ネストされた関数rectangleも変更する必要があります。
繰り返しますが、 よりもさらに上のオブジェクトを直接要求する必要がないようにメソッドを構成している場合this、この問題は発生しません...

...しかし、次のようなインターフェースがある場合:

MyApp.myServices.webService.send();

そして、それは見つけることを期待しています:

MyApp.appData.user.tokens.latest;  // where personally, I might leave tokens in a closure

appData モジュールの構造を変更すると、古い形式へのすべての参照を見つけてすべての名前を変更するまで、webService モジュールにあらゆる種類のエラーが発生します。

于 2013-03-30T14:37:13.797 に答える