なぜ同じ行で匿名関数を呼び出す必要があるのでしょうか?
-
16-09-2019 - |
質問
クロージャに関するいくつかの投稿を読んでいて、これをいたるところで見かけましたが、それがどのように機能するか明確な説明はありません - 毎回、それを使用するように言われるだけです...:
// Create a new anonymous function, to use as a wrapper
(function(){
// The variable that would, normally, be global
var msg = "Thanks for visiting!";
// Binding a new function to a global object
window.onunload = function(){
// Which uses the 'hidden' variable
alert( msg );
};
// Close off the anonymous function and execute it
})();
新しい匿名関数を作成して実行することがわかりました。したがって、その後、この単純なコードは機能するはずです (実際に機能します)。
(function (msg){alert(msg)})('SO');
私の質問は、ここでどんな魔法が起こるのかということです。と書いたときにこう思いました。
(function (msg){alert(msg)})
次に、関数 ""(msg) のような新しい名前のない関数が作成されます ...
しかし、それではなぜうまくいかないのでしょうか?
(function (msg){alert(msg)});
('SO');
なぜ同じ行に置く必要があるのでしょうか?
いくつかの投稿を指摘するか、説明をお願いできますか?
解決
関数定義の後にセミコロンを削除します。
(function (msg){alert(msg)})
('SO');
上記は機能するはずです。
デモページ: https://jsfiddle.net/e7ooeq6m/
この種のパターンについては、この投稿で説明しました。
編集:
見てみると ECMAスクリプト仕様, 、関数を定義するには 3 つの方法があります。(98 ページ、セクション 13 関数定義)
1.関数コンストラクターの使用
var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30
2.関数宣言を使用します。
function sum(a, b)
{
return a + b;
}
alert(sum(10, 10)); //Alerts 20;
3.関数式
var sum = function(a, b) { return a + b; }
alert(sum(5, 5)); // alerts 10
それでは、宣言と表現の違いは何なのかと疑問に思うかもしれません。
ECMA スクリプト仕様より:
関数宣言:関数識別子 ( FormalParameterListopt ){ FunctionBody }
関数式 :関数識別子opt(FormalParameterListopt){FunctionBody }
気が付けば「識別子」は オプション 関数式の場合。識別子を指定しない場合は、匿名関数が作成されます。識別子を指定できないという意味ではありません。
これは、以下が有効であることを意味します。
var sum = function mySum(a, b) { return a + b; }
注意すべき重要な点は、「mySum」は mySum 関数本体の内部でのみ使用でき、外部では使用できないことです。次の例を参照してください。
var test1 = function test2() { alert(typeof test2); }
alert(typeof(test2)); //alerts 'undefined', surprise!
test1(); //alerts 'function' because test2 is a function.
これを比較してください
function test1() { alert(typeof test1) };
alert(typeof test1); //alerts 'function'
test1(); //alerts 'function'
この知識を身につけて、コードを分析してみましょう。
次のようなコードがある場合、
function(msg) { alert(msg); }
関数式を作成しました。そして、この関数式を括弧で囲むことで実行できます。
(function(msg) { alert(msg); })('SO'); //alerts SO.
他のヒント
これは、自己呼び出される関数と呼ばれています。
あなたは(function(){})
は関数オブジェクトを返して呼び出したときに何をやっています。あなたはそれに()
を追加すると、それが起動され、体内で何かが実行されます。 ;
は、第二の呼び出しが失敗した理由です、文の終わりを意味します。
一つは、「()」の演算子をグループ化していることです。
ここでは、あなたの基本的な宣言された関数です。
例。 1:
var message = 'SO';
function foo(msg) {
alert(msg);
}
foo(message);
関数はオブジェクトであり、グループ化することができます。それでは、機能の周りに括弧を投げてみましょう。
例。 2:
var message = 'SO';
function foo(msg) { //declares foo
alert(msg);
}
(foo)(message); // calls foo
は、今の代わりに宣言すると、右の距離が同じ関数を呼び出すの、我々はそれを呼び出すようにそれを宣言するための基本的な置換を使用することができます。
例。 3ます。
var message = 'SO';
(function foo(msg) {
alert(msg);
})(message); // declares & calls foo
私たちはそれを呼び出すために名前を使用していないので、最後に、我々は、余分なfooの必要性を持っていません!機能は匿名でできます。
例。 4。
var message = 'SO';
(function (msg) { // remove unnecessary reference to foo
alert(msg);
})(message);
あなたの質問に答えるために、戻って実施例2を参照してくださいあなたの最初の行には、いくつかの無名の機能やグループ、それを宣言し、それを呼び出すことはありません。二行目のグループ文字列。どちらも、何もしません。 (ビンセント最初の例。)
(function (msg){alert(msg)});
('SO'); // nothing.
(foo);
(msg); //Still nothing.
しかし、
(foo)
(msg); //works
匿名関数は「」名前の関数ではありません。それは単に名前のない関数です。
JavaScriptで他の値と同じように、関数が作成する名前を必要としません。それははるかにより有用であるものの実際には他の値のような名前にバインドします。
しかし、他の値と同様に、あなたは時々名前にそれを結合することなく、それを使用したいです。それは自己呼び出しパターンです。
ここで結合されていない機能や数は、ある、彼らは何もしないと使用することはできません。
function(){ alert("plop"); }
2;
だから我々は、他の値と同様、それらを使用できるようにするには、変数に格納する必要があります:
var f = function(){ alert("plop"); }
var n = 2;
また、変数に関数をバインドする糖衣構文を使用することができます:
function f(){ alert("plop"); }
var n = 2;
しかし、それらを命名することは必要ではなく、より多くの混乱と少ない可読性につながるならば、あなたはちょうどそれらを離れて使用することができます。
(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5
ここで、私の機能と私の番号が変数にバインドされていない、彼らはまだ使用することができます。
このように、それは自己を呼び出す関数のように見えますが、本当の価値を持っていないと述べました。しかし、あなたは、JavaScriptのスコープデリミタが機能していないブロック({})であることを念頭に置いて維持する必要があります。
だから、自己呼び出す関数が、実際にC ++、C#やJavaのブロックと同じ意味を持っています。その内側に作成された変数がスコープ外の「リーク」しないことを意味します。これは、グローバルスコープを汚染しないようにするためにJavaScriptで非常に便利です。
これは、JavaScriptが動作するだけの方法です。あなたが名前の関数を宣言することができます:
function foo(msg){
alert(msg);
}
そして、それを呼び出します:
foo("Hi!");
それとも、あなたは匿名関数を宣言することができます:
var foo = function (msg) {
alert(msg);
}
そして、それを呼び出します:
foo("Hi!");
それとも、あなただけの名前に関数をバインドすることはできません。
(function(msg){
alert(msg);
})("Hi!");
関数も関数を返すことができます:
function make_foo() {
return function(msg){ alert(msg) };
}
(make_foo())("Hi!");
これはmake_foo
のボディに「VAR」と定義されたすべての変数はmake_foo
によって返された各機能によりオーバー閉鎖される何も価値があります。これは閉鎖され、それは一つの機能によって値に対して行われた変更は、別て可視であることを意味します。
このあなたが望む場合は、情報をカプセル化することができます:
function make_greeter(msg){
return function() { alert(msg) };
}
var hello = make_greeter("Hello!");
hello();
これは、どれだけほぼすべてのプログラミング言語ですが、Javaが動作します。
あなたが示したコード、
(function (msg){alert(msg)});
('SO');
2 の文で構成されています。最初は(それが保存されていないため、その後のガベージが収集される)関数オブジェクトを与える式です。二つ目は、文字列を生成する式です。文字列に関数を適用するには、それが作成されたとき(あなたはまた、上記の表示された)関数の引数として文字列を渡す必要がありますいずれか、またはあなたが、実際には変数で関数を格納する必要があります。あなたができるように、あなたのレジャーで、後でそれを適用します。これと同様ます:
var f = (function (msg){alert(msg)});
f('SO');
変数に匿名関数(ラムダ関数)を格納することによって、あなたが効果的に名前を与えていることに注意してください。したがって、あなただけのようにも通常の関数を定義することができます:
function f(msg) {alert(msg)};
f('SO');
前のコメントの要約ます:
function() {
alert("hello");
}();
変数に割り当てられていないとき、、構文エラーを生成します。コードは閉括弧は、構文的に正しくないレンダリング機能文(または定義)として解析されます。機能部の周囲に括弧を追加する
のように、インタプリタ(プログラマ)、これは関数式(または呼び出し)であることを告げます(function() {
alert("hello");
})();
これは、匿名で作成され、呼び出しは、それが宣言されているのと同じラインで発生するので、すぐに実行されることを意味、自己起動する機能です。この自己呼び出し関数は、引数なしの関数を呼び出すためにおなじみの構文で示された、プラス関数の名前の周りに括弧が追加されます。(myFunction)();
この答えは質問に対する厳密には関係ありませんが、あなたは文法機能のこの種の機能に特定ではないことを見つけるために興味があるかもしれません。たとえば、私たちは常にこのような何かを行うことができます:
alert(
{foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"
の機能に関連します。彼らはFunction.prototypeから継承したオブジェクトを、あるように、我々のようなことを行うことができます:
Function.prototype.foo = function () {
return function () {
alert("foo");
};
};
var bar = (function () {}).foo();
bar(); // alerts foo
そして、あなたが知っている、私たちもそれを実行するために括弧を持つ関数を囲む必要はありません。とにかく、限り、我々は結果を変数に割り当てようとしてています。
var x = function () {} (); // this function is executed but does nothing
function () {} (); // syntax error
あなたが関数で行うことができますもうひとつは、できるだけ早くあなたがそれらを宣言して、それらの上new
演算子を呼び出し、オブジェクトを取得することです。以下は等価です:
var obj = new function () {
this.foo = "bar";
};
var obj = {
foo : "bar"
};
機能は持っていJavaScriptの1つの以上の特性があります。あなたは再帰的に同じ匿名関数を呼び出したい場合ます。
(function forInternalOnly(){
//you can use forInternalOnly to call this anonymous function
/// forInternalOnly can be used inside function only, like
var result = forInternalOnly();
})();
//this will not work
forInternalOnly();// no such a method exist
アスカーの質問の私の理解では、そのようなことです
この魔法の作業を行い方法:
(function(){}) ('input') // Used in his example
私が間違っている可能性があります。しかし、人々は精通していることを通常の実施は、次のとおりです。
(function(){}('input') )
その理由は、JavaScriptがAKAの()
括弧、ステートメントを含めることはできませんし、パーサがfunctionキーワードに遭遇したとき、それは関数式ではなく関数の宣言としてそれを解析するために知っているようなものである。
ソース:ブログ記事の直後、呼び出される関数の式(生命維持)する の
括弧なしの例:
void function (msg) { alert(msg); }
('SO');
(これは私の知る限り、ボイドの唯一の本当の使用である)
または
var a = function (msg) { alert(msg); }
('SO');
または
!function (msg) { alert(msg); }
('SO');
と同様に動作します。 void
は評価する式だけでなく、割り当てと強打を引き起こしています。最後のものは~
、+
、-
、delete
、typeof
、単項演算子(void
も同様です)の一部で動作します。働いていないので、変数の要件のクーゼの++
、--
である。
改行は必要ありません。
これは自己実行型の匿名関数です。最初の括弧のセットには実行される式が含まれており、2 番目の括弧のセットはそれらの式を実行します。
(function () {
return ( 10 + 20 );
})();
Peter Michaux がその違いについて語ります。 重要な括弧のペア.
これは、親名前空間から変数を非表示にしようとする場合に便利な構造です。関数内のすべてのコードは関数のプライベート スコープに含まれます。つまり、関数の外部からはまったくアクセスできず、完全にプライベートになります。
見る:
ビューのもう一つのポイント
まず、あなたが匿名関数を宣言することができます:
var foo = function(msg){
alert(msg);
}
次に、あなたはそれを呼び出すます:
foo ('Few');
ための FOO =関数(MSG){アラート(MSG);}あなたが交換できるようにするの FOOするとして
function(msg){
alert(msg);
} ('Few');
しかし、あなたは解析時に関数を宣言の構文エラーを回避するために、カッコの組の内側にあなたの全体の無名関数をラップする必要があります。その後、我々が持っている、
(function(msg){
alert(msg);
}) ('Few');
この方法では、それは簡単に私のために理解しています。
あなたがやったときます:
(function (msg){alert(msg)});
('SO');
あなたは('SO')
の前にあるため、セミコロンの機能を終了します。あなただけ書いた場合:
(function (msg){alert(msg)})
('SO');
これは動作します。
それが動作しない理由は、単純な理由は、匿名関数の終了を示す;
のではありません。関数呼び出しの終わりに()
せず、それは関数呼び出しではないからです。つまり、
function help() {return true;}
あなたはresult = help();
を呼び出した場合、これは関数の呼び出しで、trueを返します。
あなたはresult = help;
を呼び出した場合、このコールではありません。これは、ヘルプが生じるように割り当てられるデータと同様に扱われる割り当てである。
あなたはセミコロンを追加することにより、匿名関数をインスタンス化/宣言してやった、
(function (msg) { /* Code here */ });
とその関数に名前がないので明らかに...ただカッコ使用して別の文でそれを呼び出そうとしましたが、これは動作しません。
('SO');
あなたはこのようにそれをしなかった場合でも、インタプリタは新しい命令/文のように、第2ライン目の括弧を見ているので、それは動作しません。
(function (msg){/*code here*/});('SO');
それはまだ動作しませんが、インタプリタが空白と馬車を無視し、1文として完全なコードを見ているので、あなたはセミコロンを削除するとそれが動作します。
(function (msg){/*code here*/}) // This space is ignored by the interpreter
('SO');
結論:関数呼び出しが即ち、のonload =「ヘルプ」、そのような別の関数によって呼び出されるような特定の条件下でない限り端に()
ずに関数呼び出しでない括弧はなかったにもかかわらず、ヘルプ機能を実行することになります付属。私はのsetTimeoutとのsetIntervalは、あまりにも、関数呼び出しのこのタイプを許可すると信じて、私も通訳がに戻って私たちをもたらしとにかく舞台裏括弧は「関数呼び出しが括弧なしの関数呼び出しではありません」が追加されますと信じています。
(function (msg){alert(msg)})
('SO');
これは、多くのJavaScriptフレームワークを使うクロージャとして匿名関数を使用する一般的な方法である。
コードがコンパイルされるときにと呼ばれるこの機能は自動的である。
最初の行で;
を配置した場合、コンパイラは、二つの異なる行として扱わ。だから、上記と同じ結果を得ることができません。
このは、のように書くこともできます:
(function (msg){alert(msg)}('SO'));
詳細については、ののJavaScript /無名関数の。
無名関数は、 実行中。無名関数と呼ばれるのは、 通常の関数と同じ方法で名前を付けます。
無名関数は、代わりに関数演算子を使用して宣言されます 関数宣言の関数演算子を使用して、次のことができます 式を配置できる場所に新しい関数を作成します。対して たとえば、新しい関数をパラメーターとして宣言できます。 関数呼び出し、または別のオブジェクトのプロパティを割り当てることができます。
名前付き関数の典型的な例を次に示します。
function flyToTheMoon() {alert("ズーム!ズーム!ズーム!");} flyToTheMoon();以下は、匿名として作成された同じ例です 機能:
var flyToTheMoon = function() {alert("ズーム!ズーム!ズーム!");} flyToTheMoon();
詳細については、こちらをお読みください。
http://helephant.com/2008/08/23/javascript-anonymous-functions/
生命維持には、単に機能を区分すると、グローバルな名前空間を「汚染」しないようにmsg
変数を隠します。あなたが数十億ドル規模のウェブサイトを構築されていない限り、現実には、単純な、それを維持し、以下のように行います。
var msg = "later dude";
window.onunload = function(msg){
alert( msg );
};
あなたはの明かすモジュールのパターンのように使用してmsg
プロパティを名前空間ができ
var myScript = (function() {
var pub = {};
//myscript.msg
pub.msg = "later dude";
window.onunload = function(msg) {
alert(msg);
};
//API
return pub;
}());
匿名関数は、それはあなたが提供された入力からのあなたの出力を生成するように、あなたがその場で関数を定義し、ワンショット契約であることを意味しています。あなたが入力を提供しなかったことを除いて。代わりに、二行目(「SO」)上で何かを書きました。 - 機能とは何の関係もない独立した声明。あなたは何を期待したのですか? :)