私は最近多くのJavascriptを読んでいて、インポートされる.jsファイルでファイル全体が次のようにラップされていることに気づきました。
(function() {
...
code
...
})();
コンストラクター関数の単純なセットではなく、これを行う理由は何ですか?
私は最近多くのJavascriptを読んでいて、インポートされる.jsファイルでファイル全体が次のようにラップされていることに気づきました。
(function() {
...
code
...
})();
コンストラクター関数の単純なセットではなく、これを行う理由は何ですか?
回答:
これは通常、名前空間(後述)に割り当てられ、メンバー関数や変数の表示を制御します。オブジェクト定義のように考えてください。その技術名は、Immediately Invoked Function Expression(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() { ... })()
がしていることは、あなたは括弧の最初のセットの中のコードを関数リテラルにすることです(つまり、「オブジェクト」全体が実際には関数であることを意味します)。その後、()
先ほど定義した関数(最後の)を自己起動します。先に述べたように、これの主な利点は、プライベートメソッド/関数とプロパティを持つことができることです:
(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」グローバル変数と、より有名な「$」グローバル変数を定義することです。
;(function(jQ) { ... code ... })(jQuery);
この例では、スクリプトをセミコロンで省略しても、特にスクリプトを縮小して他のスクリプトと連結しようとする場合は、セミコロンを省略しても問題はありません
(function (context) { ..... })(this)
を行うことにより、コンテキストを渡すことができます。これにより、親コンテキストに好きなものをアタッチして、それを公開できます。
最も簡単な形式では、この手法はコードを関数スコープ内にラップすることを目的としています。
以下の可能性を減らすのに役立ちます。
それはしない文書の準備ができたときを検出-それはいくつかの種類ではありません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
ある日、誰かが「すぐに実行するだけでよいので、 '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
次のステップは、「var myMainFunction =
私たちがそれを使用しないのならなぜあるのか!?」という考えです。
答えは簡単です。以下のように削除してみてください。
function(){ console.log('mamamia!'); }();
「関数宣言は起動できない」ため、機能しません。
トリックは、削除するvar myMainFunction =
ことで関数式を関数宣言に変換したことです。詳細については、「リソース」のリンクを参照してください。
次の質問は、「なぜそれを関数式として保持できないのvar myMainFunction =
ですか?
答えは「あなたができる」で、あなたがこれを行うことができます多くの方法実際にあります追加+
、!
、-
、または多分(それは今大会で行うのと)括弧のペアで包み、そしてより多くの私は信じては。例として:
(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
基本的に、現在のスコープで宣言されていない変数に値が割り当てられている場合、「変数が見つかるか、グローバルスコープに到達するまで(スコープが作成される)、スコープチェーンのルックアップが行われます」。
ブラウザー環境(nodejsのようなサーバー環境に対して)の場合、グローバルスコープはwindow
オブジェクトによって定義されます。したがって、私たちは行うことができますwindow.myOtherFunction()
。
このトピックに関する私の「グッドプラクティス」のヒントは、何かを定義するときに常に使用var
することですです。それが数値、オブジェクト、または関数であるかどうか、さらにはグローバルスコープ内であってもです。これにより、コードがはるかに簡単になります。
注意:
block scope
(更新:ES6で追加されたブロックスコープのローカル変数た)。function scope
&global scope
(window
ブラウザ環境ではスコープ)しかないについてもっと読むJavascript Scopes
:
このIIFE
概念をmodule pattern
理解したら、それはにつながります。これは、通常、このIIFEパターンを利用することによって行われます。楽しんで :)
ブラウザのJavaScriptには、実際には関数スコープとグローバルスコープという2つの有効なスコープしかありません。
変数が関数スコープにない場合、グローバルスコープにあります。そして、グローバル変数は一般的に悪いので、これはライブラリの変数をそれ自体に保つための構造です。
それはクロージャーと呼ばれています。基本的には関数内のコードを封印し、他のライブラリがコードに干渉しないようにします。これは、コンパイルされた言語で名前空間を作成することに似ています。
例。私が書いたとしましょう:
(function() {
var x = 2;
// do stuff with x
})();
これで、他のライブラリがx
、ライブラリで使用するために作成した変数にアクセスできなくなりました。
(function(){ ... return { publicProp1: 'blah' }; })();
。明らかに名前空間と完全に平行ではありませんが、そのように考えると役立つかもしれません。
一部の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;
})()
}
また、スコープ関数で「use strict」を使用して、コードが「strictモード」で実行されるようにする必要があります。以下に示すサンプルコード
(function() {
'use strict';
//Your code from here
})();