web-dev-qa-db-ja.com

IIFEを使用してmodule.exportsを定義する理由はありますか?

私のチームには経験豊富なJS開発者はいませんが、Nodeでライブラリを作成していて、実際のJS開発者から「私たちはjsをよりモジュール化する必要があります-汚染しないように」という提案を受けましたグローバルネームスペースを使用し、初心者が読みやすくするために」と、次のように指示しました。

_module.exports = (function(){
      return {
         nameToExpose: functionToExpose
         ...
    };
})();
_

のではなく

_module.exports.nameToExpose = functionToExpose;
_

もしあれば、これの意味は何ですか?後者は、IIFEがスコープとするローカル宣言を行わず、たとえそうであっても、モジュールファイルに対してローカルであり、require() sを実行するプログラム全体に対してグローバルではありません。

私が読んだIIFEの説明は他にもたくさんありますが(上記のコメントに要約されています)、このサイトについてグーグルで調べたり、この特定の質問に答えたりすることはありません。一部のテストでは、後者がnotが実際にfunctionToExposeをグローバル名前空間に配置していることを明らかにしていますが、元の名前は関数タイプ自体に記録されています。

18
Ryan Reich

ほとんど違いはありません。 Node.jsの全体的なアイデアは、requireを使用し、モジュールを使用するなど、特に懸念事項を分離することです。 (注意して)正しく実行していれば、あらゆる種類のグローバルスコープの "汚染"について心配する必要はないはずです。 _module.exports_内のすべてがそのモジュールに存在します。

フロントエンドのものを扱っているとき、それはグローバルスコープが問題になるときです。なぜなら、関数または何かがスコープされていない場合(つまり、IIFEまたは他の関数ブロック内)は、グローバルwindowオブジェクト、その他すべてがその関数にアクセスできます。

本物のJS開発者

赤い旗である誰かを呼び出す。

グローバル名前空間を汚染せず、新規参入者が読みやすくする

コードを正しくモジュール化していれば、それは問題になりません。 IIFEには時間と場所がありますが、IIFEですべてをラップするすでにモジュール内にのようにコードを魔法のように「モジュール化」するか、もっと読みやすくする理由はわかりません設計されたようにNode.jsを使用するだけでなく、「新参者」に:

_module.exports = function() { ... } // whatever
_

たとえそうであっても、それらはモジュールファイルに対してローカルであり、それをrequire() sするプログラム全体に対してグローバルではありません。

あなたは正しいです。私は彼が言っていることは何でも塩の粒でとるでしょう。多分彼は彼のアプローチが過去に彼に役立ったいくつかの特定のユースケースを知っているので、私は彼に具体的にそれについて彼に尋ねて彼の発言を見てもらいたいと思います。それ以外は、あなたは正しい方向に進んでいるように感じます。

17
Josh Beam

たぶん時々これを行う理由は、そうしないと、module.exportsオブジェクトのスコープはファイル全体にする必要があります。

次の2つの方法を検討してください。

  1. IIFEなし。

    var foo = 'la' + 'la';  // some computed value
    
    //
    // ... lots of program code here ...
    //
    
    module.exports = {
        foo : foo,
    };
    
  2. IIFEを使用。

    //
    // ... lots of program code here ...
    //
    
    module.exports = (function () {
        var foo = 'la' + 'la';  // some computed value
        return {
            foo : foo
        }
    }());
    

最初の例では、2つの問題が発生します。

  1. 変数(fooなど)は、モジュールから値をエクスポートするために使用される場所からかなり離れた場所に作成されます。これにより、明瞭さが低下する可能性があります。確かに、プログラムコードの後に​​変数を宣言することはできますが、それでもスコープは同じです(そしてvarsは hoisted です)。さらに、一般的なベストプラクティスは、すべての変数を事前に宣言することです。そうしないと、考慮すべきトレードオフになります。
  2. プログラムコードは、意図的または偶然に変数を乱雑にする可能性があり、状況を複雑にし、それが必要でない限り(場合によっては)望ましくありません。

2番目の例では、ファイルのその領域にプライベートスコープを設定することで、これらの問題を排除しています。ファイル全体をスコープとする変数を引き続き使用できますが、それが必要ない場合は、読みやすく理解しやすい変数を使用できます。

多くの場合、マシンではなく人間向けにプログラミングします。これは前者の最適化の例です。

更新:

JavaScriptの最新バージョンでは、 const および let が、このパターンが解決しようとしている問題のおそらくより良い解決策です。それらを使用すると、IIFEが保護しようとしているのと同じミスをした場合にエラーをスローするように変数を定義できます。

//
// ... lots of program code here ...
//

const foo = 'la' + 'la';  // some computed value

module.exports = {
    foo : foo,
};

上記の例では、プログラムコードがfooを使用する場合、ReferenceErrorundefinedとして受け取るのではなく、 Temporal Dead Zone のためにvarでクラッシュします。これは、fooの宣言を意図的に使用する場合は明示的にコードの前の場所に移動するか、コードを修正する必要があるため、すばらしいです。

9
Seth Holladay