12

これらのパターンを何と呼びますか?それらの違いは何ですか?それぞれをいつ使用しますか?他に似たようなパターンはありますか?

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

編集:最後の2つのケースで関数に名前を付けることで、これを行うための2つの一見冗長な方法を見つけました...

var a = (function foo() {
    console.log(this);  // window
})();

var b = function bar() {
    console.log(this);
}();

EDIT2 : これは@GraceShaoによって提供される別のパターンで、関数スコープの外で関数にアクセスできるようにします。

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}

// I played with this as well 
// by naming the inside function 
// and got the following:

(foo = function bar() {
    console.log(this);  // window
    console.log(foo);   // function bar() {}
    console.log(bar);   // function bar() {}
})();
console.log(foo);       // function bar() {}
console.log(bar);       // undefined
4

6 に答える 6

36

これがあなたの関数であり、いつ/なぜそれらが役立つかもしれないかを説明するいくつかのコメントがあります:

(function() {
    // Create a new scope to avoid exposing 
    // variables that don't need to be
    // This function is executed once immediately
})();

(function fact(i) {
    // This named immediately invoked function 
    // is a nice way to start off recursion
    return i <= 1 ? 1 : i*fact(i - 1);
})(10);

var y = (function() {
    // Same as the first one, but the return value 
    // of this function is assigned to y
    return "y's value";
})();

var z = function() {
    /* This is the exact same thing as above 
     (except it is assigned to z instead of y, of course).
     The parenthesis in the above example don't do anything
     since this is already an expression
    */
}();
于 2012-06-11T17:23:08.773 に答える
6

この場合、それらはすべて意味的に同一です。ECMAScript仕様には完全な本番ルールが含まれているため、これは大幅に簡略化されています。

また、名前が使用されていないため、名前付き関数の名前(x)を無視していることに注意してください。本体内で参照することもできますが、(文法生成を介して)FunctionExpressionであるため、(正しいJS実装では)含まれているスコープを汚染することはありません。コメントを参照してください。

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

削減(この場合、本文は重要ではなく、すべて「未定義を返します」):

(function() {})();

(function x() {})();

var y = (function() {})();

var z = function() {}();

削減(ECMAScriptの文法FunctionExpressionは実動規則ですが、ここでは「関数である式」を意味するために使用します):

FunctionExpression()

FunctionExpression()

var y = FunctionExpression()

var z = FunctionExpression()

結果の割り当て(常にそうなるundefined)を無視すると、すべての形式が同じであることがわかります。

ハッピーコーディング。

于 2012-06-11T17:31:59.317 に答える
2

自己呼び出し匿名関数。関数本体はすぐに呼び出されます。

(function() {
    console.log(this);  // window
})();

自己呼び出し機能。関数本体はすぐに呼び出されます。x関数本体内で関数を参照することもできます。したがって、何かをすぐに実行したい場合、そしてそれを繰り返したい場合は、それを直接参照することができます。

(function x() {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();

右側の自己呼び出し無名関数がすぐに呼び出され、戻り値がに割り当てられますy。通常、このパターンを使用すると戻り値があります。それ以外の場合、yはになりますundefined

var y = (function() {
    console.log(this);  // window
})();

IMO、3つ目と同じです。関数を囲む3番目の括弧は、関数を1つの全体のように見せるためのものです。しかし、両方の機能は同じです。

var z = function() {
    console.log(this);  // window
}();

2番目のものと似ていますが、次を使用して関数スコープの外でxを参照できます。

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}
于 2012-06-11T17:34:32.113 に答える
0

(function(){ 'usestrict'; このタイプを使用できます

理由:IIFE-即時呼び出し関数式は、グローバルスコープから変数を削除します。これにより、変数と関数宣言がグローバルスコープで予想よりも長く存続するのを防ぐことができ、変数の衝突を回避することもできます。

理由:コードを縮小して1つのファイルにバンドルし、本番サーバーにデプロイすると、変数と多くのグローバル変数が衝突する可能性があります。IIFEは、各ファイルに可変スコープを提供することにより、これらの両方からユーザーを保護します。

于 2014-11-21T04:07:28.583 に答える
0

ES06を使用する時が来ました。これがES06の矢印関数を使用した関数です。

 (() => {
    // Create a new scope to avoid exposing variables that don't need to be
    // This function is executed once immediately
})();

(fact = (i)=>(
  // This named immediately invoked function is a nice way to start off recursion
  i <= 1 ? 1 : i*fact(i - 1)
))(10)

const y = (() => (
    // Same as the first one, but the return value of this function is assigned to y
     "y's value"
))();

const z = (() => {
    // This is the exact same thing as above (except it's assigned to z instead of y, of course).
    // The parenthesis in the above example don't do anything since this is already an expression
})();
于 2018-05-23T12:33:48.530 に答える
0

ブラウザのJavaScriptには、名前空間がありません。すべてのコードはグローバルスコープで実行されます。したがって、内部アプリケーションコードまたはサードパーティの依存関係は、独自の機能を公開しながらスコープを汚染する可能性があります。グローバル名前空間を汚染すると、名前の衝突が発生します。この名前の衝突は大規模なプロジェクトでは非常に一般的であり、非常に有害な場合があります。

たとえば、サードパーティのライブラリがutilsというグローバル変数をインスタンス化するとします。他のライブラリまたはアプリケーションコード自体が誤ってutilsをオーバーライドまたは変更した場合、それに依存するコードが予期しない方法でクラッシュする可能性があります。他のライブラリまたはアプリケーションコードが、内部使用のみを目的とした別のライブラリの関数を誤って呼び出した場合にも、予測できない副作用が発生する可能性があります。

 (function () {
      // create state variables
      // make some operation
      // then return those
      const export = {
           export1: () => {},
           export2: () => {}
      }
      return exported
})()

プライベートスコープを作成するために使用され、パブリックにすることを目的としたパーツのみをエクスポートします。

関数式を括弧で囲みます

なぜそれらが必要なのですか?その理由は純粋に構文上のものです。JavaScriptパーサーは、関数宣言と関数式を簡単に区別できる必要があります。関数式の前後の括弧を省略し、即時呼び出しを別のステートメントとして配置するとfunction(){}(3)、JavaScriptパーサーはそれの処理を開始し、キーワード関数で始まる別のステートメントであるため、関数を処理していると結論付けます。宣言。すべての関数宣言には名前が必要であるため(ここでは名前を指定していません)、エラーがスローされます。これを回避するために、関数式を括弧内に配置し、ステートメントではなく式を処理していることをJavaScriptパーサーに通知します。

一部のプロジェクトでもこれが見られる場合があります。

+function(){}();
-function(){}();
!function(){}();
~function(){}();

今回は、関数式を括弧で囲んで関数宣言と区別する代わりに、単項演算子を使用できます+ , - , ! , and ~。これは、ステートメントではなく式を処理していることをJavaScriptエンジンに通知するために行います。

于 2022-01-24T21:37:26.897 に答える