回答:
それはすべて変数スコープに関するものです。自己実行関数で宣言された変数は、デフォルトでは、自己実行関数内のコードでのみ使用できます。これにより、JavaScriptコードの他のブロックで変数がどのように命名されるかを気にすることなくコードを記述できます。
たとえば、アレクサンダーのコメントで述べたように:
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
が定義されていないため3
、最初にログに記録され、次にエラーがスローされます。console.log
foo
var
で実行すると、次のようになり...function(){ foo=3;}
ます。グローバル変数を設定しますよね?
function(){ var foo = 3; alert(foo); }; alert(foo);
だから私はまだそれを得ることはありません
単純化。とても正常に見えるので、ほとんど快適です:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
ただし、高度な文字を基本レベルの表現に変換する非常に便利なJavaScriptライブラリをページに組み込んだ場合はどうなりますか?
待って...何?
つまり、誰かが何らかのアクセントの付いた文字を入力したが、プログラムに「英語」の文字AZだけが欲しいのですか?まあ...スペイン語の「ñ」とフランス語の「é」の文字は、「n」と「e」の基本文字に変換できます。
だから、誰かが私のサイトに含めることができる包括的なキャラクターコンバーターを書いています...私はそれを含めます。
1つの問題:それは私の関数と同じ「名前」と呼ばれる関数を持っています。
これは衝突と呼ばれるものです。同じスコープで同じ名前で宣言された2つの関数があります。これは避けたいです。
したがって、コードのスコープをどうにかする必要があります。
JavaScriptでコードをスコープする唯一の方法は、コードを関数でラップすることです。
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
それで問題が解決するかもしれません。これですべてが囲まれ、開始および終了中括弧内からのみアクセスできます。
私たちは関数の中に関数を持っています...これは見た目には奇妙ですが、完全に合法です。
問題は1つだけです。私たちのコードは機能しません。userName変数がコンソールにエコーされることはありません!
この問題は、既存のコードブロックの後に関数への呼び出しを追加することで解決できます...
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
main();
または前に!
main();
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
二次的な懸念:「メイン」という名前がまだ使用されていない可能性は何ですか?...とても、とてもスリムです。
もっとスコーピングが必要です。そして、main()関数を自動的に実行するいくつかの方法。
次に、自動実行機能(または自己実行、自己実行など)について説明します。
((){})();
構文は罪として厄介です。ただし、機能します。
関数定義をかっこで囲み、パラメーターリスト(別のセットまたはかっこ!)を含めると、関数呼び出しとして機能します。
それでは、いくつかの自己実行構文を使用して、コードをもう一度見てみましょう。
(function main() {
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
)();
したがって、あなたが読んだほとんどのチュートリアルでは、「匿名の自己実行」という用語や類似の用語が攻撃されます。
長年の専門的な開発の後、私はあなたがデバッグの目的で書くすべての関数に名前を付けることを強くお勧めします。
何かがうまくいかない場合(そしてそれがうまくいかない場合)は、ブラウザーでバックトレースを確認します。スタックトレースのエントリに名前が付いていると、コードの問題を絞り込むのが常に簡単になります。
非常に長い間、それが役に立てば幸いです!
:)
自己呼び出し(自動呼び出しとも呼ばれます)は、関数がその定義と同時に実行される場合です。これはコアパターンであり、JavaScript開発の他の多くのパターンの基盤として機能します。
私はそれが大好きです:)
非常に–(なぜそれを良いと言うべきなのか?)
詳細はこちら。
名前空間。JavaScriptのスコープは関数レベルです。
暗黙のグローバルについて言及している回答はどれも信じられません。
(function(){})()
構築物は、私にはこれが大きな関心事である、暗黙のグローバル保護することはできません参照http://yuiblog.com/blog/2006/06/01/global-domination/
基本的に、ファンクションブロックは、定義したすべての依存する「グローバル変数」がプログラムに限定されていることを確認します。暗黙的なグローバルの定義から保護しません。JSHintなどは、この振る舞いをどのように防ぐかについての推奨を提供できます。
より簡潔なvar App = {}
構文は、同様のレベルの保護を提供し、「パブリック」ページ上ではファンクションブロックにラップされます。(この構成を使用するライブラリの実際の例については、Ember.jsまたはSproutCoreを参照してください)
限りprivate
性質が行く、彼らは親切あなたが公共のフレームワークやライブラリを作成している場合を除き過大評価のですが、あなたがそれらを実装する必要がある場合は、ダグラス・クロックフォードは、いくつかの良いアイデアを持っています。
私はすべての回答を読みましたが、非常に重要なものがここにありません。キスします。主な理由は2つあります。なぜ自己実行の匿名関数が必要なのか、または「すぐに呼び出される関数式(IIFE)」の方が良いと言えます。
最初のものは非常によく説明されています。2つ目については、次の例を検討してください。
var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());
注意1:関数をMyClosureObject
に割り当てているわけではありません。さらに、その関数を呼び出した結果です。()
最後の行で注意してください。
注意2: JavaScriptの関数についてさらに知っておくべきことは、内部関数が関数のパラメーターと変数にアクセスできることです。これらは内部で定義されています。
いくつかの実験をしてみましょう:
私はMyName
使うことができgetMyName
、それはうまくいきます:
console.log(MyClosureObject.getMyName());
// Michael Jackson RIP
次の巧妙なアプローチは機能しません。
console.log(MyClosureObject.MyName);
// undefined
しかし、別の名前を設定して、期待される結果を得ることができます。
MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName());
// George Michael RIP
編集:上記の例でMyClosureObject
は、new
接頭辞なしで使用するように設計されているため、慣例により大文字にしないでください。
パラメータがあり、「コードのブランチ」は関数を返しますか?
var a = function(x) { return function() { document.write(x); } }(something);
閉鎖。の値はsomething
、に割り当てられた関数によって使用されa
ます。something
いくつかの変化する値(forループ)を持つ可能性があり、aに新しい関数があるたびに。
var x = something;
外部関数で明示的な方が好きx
です。imoの方がこの方法で読みやすくなります...
x
し、字句スコープに直接依存する場合、新しい値が使用されます。つまり、document.write(something)
...
おそらくスコープの分離。関数宣言内の変数が外部の名前空間を汚染しないように。
もちろん、世の中にあるJS実装の半分については、とにかくそうなるでしょう。
自己呼び出しの匿名関数がどのように役立つかを示す確かな例を次に示します。
for( var i = 0; i < 10; i++ ) {
setTimeout(function(){
console.log(i)
})
}
出力: 10, 10, 10, 10, 10...
for( var i = 0; i < 10; i++ ) {
(function(num){
setTimeout(function(){
console.log(num)
})
})(i)
}
出力: 0, 1, 2, 3, 4...
let
代わりにvar
最初のケース大丈夫でしょう。
JavaScriptの自己呼び出し関数:
自己呼び出し式は、呼び出されることなく、自動的に呼び出されます(開始されます)。自己呼び出し式は、作成された直後に呼び出されます。これは基本的に、名前の競合を回避するため、およびカプセル化を実現するために使用されます。変数または宣言されたオブジェクトは、この関数の外部からはアクセスできません。最小化(filename.min)の問題を回避するには、常に自己実行関数を使用してください。
自己実行関数は、変数のスコープを管理するために使用されます。
変数のスコープは、それが定義されているプログラムの領域です。
グローバル変数にはグローバルスコープがあります。これは、JavaScriptコードのあらゆる場所で定義されており、関数内でも、スクリプト内のどこからでもアクセスできます。一方、関数内で宣言された変数は、関数の本体内でのみ定義されます。これらはローカル変数であり、ローカルスコープを持ち、その関数内でのみアクセスできます。関数パラメーターもローカル変数としてカウントされ、関数の本体内でのみ定義されます。
以下に示すように、関数内でグローバル変数変数にアクセスできます。また、関数の本体内では、ローカル変数が同じ名前のグローバル変数よりも優先されることに注意してください。
var globalvar = "globalvar"; // this var can be accessed anywhere within the script
function scope() {
alert(globalvar);
localvar = "localvar" //can only be accessed within the function scope
}
scope();
したがって、基本的に自己実行機能により、JavaScriptコードの他のブロックで変数がどのように命名されるかを気にせずにコードを記述できます。
短い答えは: グローバル(またはそれ以上の)スコープの汚染を防ぐことです。
IIFE(Immediately Invoked Function Expressions)は、プラグイン、アドオン、ユーザースクリプト、または他の人のスクリプトで動作することが予想されるスクリプトとしてスクリプトを記述するためのベストプラクティスです。これにより、定義した変数が他のスクリプトに望ましくない影響を与えないことが保証されます。
これは、IIFE式を記述するもう1つの方法です。私は個人的にこの次の方法を好みます:
void function() {
console.log('boo!');
// expected output: "boo!"
}();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
例から、それ以上に一度だけ実行されることが期待される機能があるため、生命維持にも効率性とパフォーマンスに影響を与えることができることは非常に明確で一度実行して、良いのための空隙にダンプされます。つまり、関数またはメソッドの宣言はメモリに残りません。
void
以前のその使用法を見ていませんでした。私はそれが好きです。
この質問に対する回答はすべて準備できているようですが、とにかく私の入力を投稿します。
自己実行機能をいつ使用したいのかわかります。
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
この関数を使用すると、追加のコードを使用して、よく使用される変数の設定や数学の方程式の実行など、よりクリーンなコードのchildObjects属性とプロパティを定義できます。ああ!またはエラーチェック。ネストされたオブジェクトのインスタンス化構文に限定されるのとは対照的に...
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
一般に、コーディングには同じことを行うための多くのあいまいな方法があり、「なぜわざわざ?」しかし、ベーシック/コアプリンシパルだけに依存できなくなった新しい状況が次々と現れています。
あなたの簡単な質問を考えてみましょう:「JavaScriptでは、いつこれを使いたいですか:...」
私は@ken_browningと@sean_holdingの回答が好きですが、ここでは言及されていない別のユースケースを示します。
let red_tree = new Node(10);
(async function () {
for (let i = 0; i < 1000; i++) {
await red_tree.insert(i);
}
})();
console.log('----->red_tree.printInOrder():', red_tree.printInOrder());
ここで、Node.insertは非同期アクションです。
関数の宣言でasyncキーワードなしで単にawaitを呼び出すことはできません。後で使用するために名前付き関数は必要ありませんが、そのinsert呼び出しを待つ必要があります。 。