630

最近、たくさんのJavascriptを読んでいて、インポートする.jsファイルでファイル全体が次のようにラップされていることに気づきました。

(function() {
    ... 
    code
    ...
})();

単純なコンストラクター関数のセットではなく、これを行う理由は何ですか?

4

9 に答える 9

833

通常、名前空間(後述)を使用して、メンバー関数や変数の可視性を制御します。オブジェクト定義のように考えてください。その技術名は、即時呼び出し関数式(IIFE)です。jQueryプラグインは通常このように書かれています。

Javascriptでは、関数をネストできます。したがって、以下は合法です。

function outerFunction() {
   function innerFunction() {
      // code
   }
}

これで、を呼び出すことができますouterFunction()が、の表示はinnerFunction()のスコープに制限されます。outerFunction()つまり、はプライベートouterFunction()です。基本的に、Javascriptの変数と同じ原則に従います。

var globalVariable;

function someFunction() {
   var localVariable;
}

対応して:

function globalFunction() {

   var localFunction1 = function() {
       //I'm anonymous! But localFunction1 is a reference to me!
   };

   function localFunction2() {
      //I'm named!
   }
}

上記のシナリオではglobalFunction()、どこからでも電話をかけることができますが、localFunction1またはに電話をかけることはできませんlocalFunction2

書くときにしていること(function() { ... })()は、最初の括弧のセット内のコードを関数リテラルにしていることです(つまり、「オブジェクト」全体が実際には関数です)。その後、()定義したばかりの関数(final)を自己呼び出しします。したがって、前述したように、これの主な利点は、プライベートメソッド/関数およびプロパティを持つことができることです。

(function() {
   var private_var;

   function private_function() {
     //code
   }
})();

最初の例では、名前で明示的に呼び出しglobalFunctionて実行します。つまり、実行するだけですglobalFunction()。ただし、上記の例では、関数を定義しているだけではありません。一度に定義して呼び出すことができます。これは、JavaScriptファイルがロードされると、すぐに実行されることを意味します。もちろん、次のことができます。

function globalFunction() {
    // code
}
globalFunction();

動作は、1つの重要な違いを除いてほぼ同じです。つまり、IIFEを使用するときにグローバルスコープを汚染することを回避します(結果として、名前がないために関数を複数回呼び出すことができないことも意味しますが、この関数は、実際には問題にならない場合にのみ実行することを目的としています)。

IIFEの優れた点は、内部で物事を定義し、必要な部分のみを外部に公開できることです(名前空間の例で、基本的に独自のライブラリ/プラグインを作成できます)。

var myPlugin = (function() {
 var private_var;

 function private_function() {
 }

 return {
    public_function1: function() {
    },
    public_function2: function() {
    }
 }
})()

これで、電話をかけることはできmyPlugin.public_function1()ますが、アクセスすることはできませんprivate_function()。クラス定義と非常によく似ています。これをよりよく理解するために、私はいくつかのさらなる読み物のために以下のリンクをお勧めします:

編集

言及するのを忘れました。その決勝()では、あなたはあなたが中に望むものを何でも渡すことができます。たとえば、jQueryプラグインを作成するときは、次のように渡しjQueryます。$

(function(jQ) { ... code ... })(jQuery) 

したがって、ここで行っているのは、1つのパラメーター(jQローカル変数と呼ばれ、その関数にのみ知られている)を受け取る関数を定義することです。次に、関数を自己呼び出しし、パラメーターを渡します(これも呼ばれますjQueryが、これは外部からのものであり、実際のjQuery自体への参照です)。これを行う緊急の必要はありませんが、いくつかの利点があります。

  • グローバルパラメータを再定義して、ローカルスコープで意味のある名前を付けることができます。
  • スコープチェーンをグローバルスコープに移動するよりも、ローカルスコープで検索する方が高速であるため、パフォーマンスがわずかに向上します。
  • 圧縮(縮小)には利点があります。

先ほど、これらの関数が起動時に自動的に実行される方法について説明しましたが、これらの関数が自動的に実行される場合、誰が引数を渡しますか?この手法は、必要なすべてのパラメーターがすでにグローバル変数として定義されていることを前提としています。したがって、jQueryがグローバル変数としてまだ定義されていない場合、この例は機能しません。ご想像のとおり、jquery.jsが初期化中に行うことの1つは、「jQuery」グローバル変数と、より有名な「$」グローバル変数を定義することです。これにより、jQueryがインクルードされた後にこのコードが機能します。

于 2010-03-11T01:32:59.407 に答える
82

要するに

概要

最も単純な形式では、この手法はコードを関数スコープ内にラップすることを目的としています。

次の可能性を減らすのに役立ちます。

  • 他のアプリケーション/ライブラリとの衝突
  • 上位の (グローバルである可能性が最も高い) スコープの汚染

ドキュメントの準備ができたときは検出しませdocument.onloadん。window.onload

Immediately Invoked Function Expression (IIFE)一般にまたはとして知られていSelf Executing Anonymous Functionます。

コードの説明

var someFunction = function(){ console.log('wagwan!'); };

(function() {                   /* function scope starts here */
  console.log('start of IIFE');

  var myNumber = 4;             /* number variable declaration */
  var myFunction = function(){  /* function variable declaration */
    console.log('formidable!'); 
  };
  var myObject = {              /* object variable declaration */
    anotherNumber : 1001, 
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
})();                           /* function scope ends */

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

上記の例では、関数で定義された(つまり、を使用して宣言されたvar)変数は「プライベート」であり、関数スコープ内でのみアクセスできます(Vivin Paliathが述べているように)。つまり、これらの変数は、関数の外では表示/到達できません。ライブデモをご覧ください

Javascript には関数スコープがあります。「関数で定義されたパラメーターと変数は関数の外では見えず、関数内のどこでも定義された変数は関数内のどこでも見えます。」(「Javascript: 良い部分」より)。


詳細

代替コード

最後に、前に投稿したコードは次のようにすることもできます。

var someFunction = function(){ console.log('wagwan!'); };

var myMainFunction = function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = { 
    anotherNumber : 1001, 
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
};

myMainFunction();          // I CALL "myMainFunction" FUNCTION HERE
someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

ライブデモをご覧ください


ルーツ

反復 1

ある日、「すぐに実行したいだけなので、'myMainFunction' という名前を付けるのを避ける方法があるに違いない」と考えた人もいるでしょう。

基本に立ち返ると、次のことがわかります。

  • expression: 値に評価されるもの。すなわち3+11/x
  • statement: 何かを実行しているが値に評価されないコード行。すなわちif(){}

同様に、関数式は値に評価されます。そして、結果の 1 つ (と思いますか?) は、それらをすぐに呼び出すことができるということです。

 var italianSayinSomething = function(){ console.log('mamamia!'); }();

したがって、より複雑な例は次のようになります。

var someFunction = function(){ console.log('wagwan!'); };

var myMainFunction = function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = { 
    anotherNumber : 1001, 
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
}();

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

ライブデモをご覧ください

反復 2

次のステップは、「var myMainFunction =使わないのになぜあるの!?」という考えです。

答えは簡単です: 以下のようにこれを削除してみてください:

 function(){ console.log('mamamia!'); }();

ライブデモをご覧ください

「関数宣言は呼び出し可能ではない」ため、機能しません。

秘訣は、削除することで関数式関数宣言var myMainFunction =に変換したことです。詳細については、「参考文献」のリンクを参照してください。

次の質問は、「 以外の関数式として保持できないのはなぜvar myMainFunction =ですか?

答えは「できます」であり、実際にはこれを行う方法はたくさんあります: a +、 a !、 aを追加する-か、またはペアの括弧で囲む (慣例で行われているように) などです。例として:

 (function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.

また

 +function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console

また

 -function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console

したがって、関連する変更がかつての「代替コード」に追加されると、「コードの説明」の例で使用されたものとまったく同じコードに戻ります

var someFunction = function(){ console.log('wagwan!'); };

(function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = { 
    anotherNumber : 1001, 
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
})();

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

についてもっと読むExpressions vs Statements


スコープのわかりやすい解説

「関数内で変数を「適切に」定義しない場合、つまり、代わりに単純な代入を行うとどうなるか」という疑問があるかもしれません。

(function() {
  var myNumber = 4;             /* number variable declaration */
  var myFunction = function(){  /* function variable declaration */
    console.log('formidable!'); 
  };
  var myObject = {              /* object variable declaration */
    anotherNumber : 1001, 
    anotherFunc : function(){ console.log('formidable!'); }
  };
  myOtherFunction = function(){  /* oops, an assignment instead of a declaration */
    console.log('haha. got ya!');
  };
})();
myOtherFunction();         // reachable, hence works: see in the console
window.myOtherFunction();  // works in the browser, myOtherFunction is then in the global scope
myFunction();              // unreachable, will throw an error, see in the console

ライブデモをご覧ください

基本的に、現在のスコープで宣言されていない変数に値が割り当てられている場合、「変数が見つかるかグローバルスコープに到達するまで(その時点で変数が作成されるまで)スコープチェーンの検索が行われます」。

ブラウザー環境 (vs nodejs などのサーバー環境) では、グローバル スコープはwindowオブジェクトによって定義されます。したがって、私たちはすることができますwindow.myOtherFunction()

このトピックに関する私の「グッドプラクティス」のヒントは、何かを定義するときに常に使用varすることです。それが数値、オブジェクト、または関数であるかどうか、およびグローバルスコープにある場合でも。これにより、コードがはるかに簡単になります。

ノート:

  • javascript にはありませblock scope(更新: ブロック スコープのローカル変数がES6で追加されました。)
  • javascript にはfunction scope& global scope(windowブラウザ環境ではスコープ)しかありません

についてもっと読むJavascript Scopes


資力


次のステップ

このIIFE概念をmodule pattern理解すると、この IIFE パターンを活用して一般的に行われる につながります。楽しむ :)

于 2014-11-04T15:31:43.590 に答える
27

ブラウザの Javascript には、関数スコープとグローバル スコープという 2 つの有効なスコープしかありません。

変数が関数スコープ内にない場合は、グローバル スコープ内にあります。また、グローバル変数は一般的に悪いので、これはライブラリの変数をそれ自体に保持するための構造です。

于 2010-03-11T01:25:19.813 に答える
19

いわゆる閉店です。基本的に、関数内のコードを封印して、他のライブラリが干渉しないようにします。これは、コンパイル済み言語で名前空間を作成することに似ています。

例。私が書くとしましょう:

(function() {

    var x = 2;

    // do stuff with x

})();

x現在、他のライブラリは、自分のライブラリで使用するために作成した変数にアクセスできません。

于 2010-03-11T01:25:16.990 に答える
8

一部の html5 オブジェクトに対するブラウザーのサポートを判別するこの方法のように、関数クロージャーをより大きな式のデータとして使用することもできます。

   navigator.html5={
     canvas: (function(){
      var dc= document.createElement('canvas');
      if(!dc.getContext) return 0;
      var c= dc.getContext('2d');
      return typeof c.fillText== 'function'? 2: 1;
     })(),
     localStorage: (function(){
      return !!window.localStorage;
     })(),
     webworkers: (function(){
      return !!window.Worker;
     })(),
     offline: (function(){
      return !!window.applicationCache;
     })()
    }
于 2010-03-11T02:59:11.423 に答える
7

変数をローカルに保つことに加えて、グローバル変数を使用してライブラリを作成する場合に非常に便利な使用法の1つは、ライブラリ内で使用する短い変数名を付けることができます。jQueryではjQuery.noConflict()を使用してjQueryを指す$変数を無効にできるため、jQueryプラグインの作成によく使用されます。無効になっている場合でも、コードは$を使用でき、次のようにしただけで壊れることはありません。

(function($) { ...code...})(jQuery);
于 2010-03-11T01:33:07.347 に答える
1

また、スコープ関数で「use strict」を使用して、コードが「厳密モード」で実行されるようにする必要があります。以下に示すサンプルコード

(function() {
    'use strict';

    //Your code from here
})();
于 2015-11-24T06:37:09.037 に答える