なぜ同じ行で無名関数を呼び出す必要があるのですか?


374

私は閉鎖についてのいくつかの投稿を読んでいて、これをどこでも見ましたが、それがどのように機能するのか明確な説明はありません-私はちょうどそれを使用するように言われたたびに...:

// 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');

なぜ同じ行にある必要があるのですか?

私にいくつかの投稿を指摘したり、説明をいただけますか?


2
他の言語では、関連する下位レベルの構造を調べたい場合、これらは関数ポインターまたはデリゲートと呼ばれます。
Chris Moschini、2011年

17
あなたが持っている ; 1行目
Oliver Ni

それがどのように機能するかがわかったので、使用しないでください。無名関数の作成やめるべきです。ほんの数文字を追加するだけで、関数に実際の名前を付け、Javascriptコードのデバッグをはるかに簡単にすることができます。
Stijn de Witt、2014

1
ライン(function (msg){alert(msg)})('SO');はそれ自体で完全に機能します。それはあなたがその前に投稿した他の匿名関数とは何の関係もありません。これらは2つの完全に分離された匿名関数です。無名関数は名前がなく、後で参照できないため、すぐに呼び出す必要があります。
タコ2015年

回答:


380

関数定義の後にセミコロンをドロップします。

(function (msg){alert(msg)})
('SO');

上記で動作するはずです。

デモページ:https : //jsfiddle.net/e7ooeq6m/

この種類のパターンについては、この投稿で説明しました。

jQueryと$の質問

編集:

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スクリプト仕様から:

FunctionDeclaration:関数識別子(FormalParameterListopt){FunctionBody}

FunctionExpression:function Identifieropt(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.

1
うん、でもなんで?なぜインラインにする必要があるのですか?空白をいくつ使ってもかまいません。
palig 2009

9
私が書いたように、セミコロンは無名関数の定義を終了しました。名前がないので(匿名です!)、それを呼び出すことができなくなります。セミコロンを付けないと、関数が実行される可能性があります。
SolutionYogi

この場合、セミコロンの自動挿入ではセミコロンが入ると思いましたが、入れません。だからあなたは正しい。
Nosredna 2009

1
Nosredna、JSはセミコロンを追加することに関してはほとんど恣意的です。この詳細な記事を読む:blog.boyet.com/blog/javascriptlessons/…–
SolutionYogi

はい(function(msg){alert(msg)})( 'SO'); 動作します。私はなぜそれがうまくいくのか尋ねていました。これが指定されている場所、またはこれがどのようなJS機能か。だから私が呼び出すだけ:(関数(msg){alert(msg)})関数で何が起こるでしょうか?それはGCされますか?
palig 2009

129

これは、自己呼び出し関数と呼ばれます。

呼び出し時に実行していることは(function(){})、関数オブジェクトを返すことです。それに追加()すると、それが呼び出され、本体のすべてが実行されます。;第二の呼び出しが失敗した理由だと、文の終わりを意味します。


ああ、わかりました。これは、特別なJSの構文です。この説明が一番好き!シンプルで短い:)
palig 2009

身体が「評価される」と言うのは間違っていると思います。他の関数と同じように実行されます。匿名なので、参照をどこかに保存するか、すぐに実行します。
SolutionYogi

16
個人的には、「関数を呼び出す自己」という言葉さえ好きではありません。関数がそれ自体を呼び出しているわけではありません。プログラマはそれを呼び出すためにこれらの括弧を書きました。
SolutionYogi

「特別な構文」ではなく、何よりも特別です。実際、「関数名(引数){ブロック}」の形式は、はるかに「特別」です。それは実際には不要な砂糖です。しかし、これは実際に物事を起こさせるものです。
jrockway 2009

2
記事への素晴らしいリンク。誰かがこの引用符を使用する理由を注記します。「グローバルオブジェクトを保護するために、すべてのJavaScriptアプリケーションは自己呼び出し関数内に記述する必要があります。これにより、アプリケーションスコープが作成され、変数が衝突する恐れなく作成できます。他のアプリケーションと一緒に。」また、「関数が終了すると、変数は破棄され、グローバルオブジェクトは変更されません。」
yeahdixon 2013

94

混乱したのは、 "()"がグループ化演算子であることです。

基本的な宣言済み関数は次のとおりです。

例 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を参照してください。最初の行では、名前のない関数を宣言してグループ化していますが、呼び出しはしていません。2行目は文字列をグループ化します。どちらも何もしません。(ヴィンセントの最初の例。)

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

だが

(foo)
(msg); //works

6
ありがとう。あなたの例は非常に明確でした。JavaScriptの括弧がこのようにコードの意味を変更する可能性があることは知りませんでした。私はJavaのバックグラウンドを持っているので、JavaScriptを使用するほとんど毎日、JavaScriptについて何か新しい(そしてしばしば予期しない)ことを学びます。
hotshot309

5
段階的にそれを行うためのおかげで、これは私が見た他のどの説明よりもはるかに優れています。+1
Wk_of_Angmar

2
ここで主要なAHAの瞬間です。代わりに説明していただきありがとうございます。+100
FredTheWebGuy 2013

1
無名関数について私が読んだ最も良い説明の1つ。どうもありがとう!
Teknotica 2014

23

無名関数は、 ""という名前の関数ではありません。それは単に名前のない関数です。

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で非常に役立ちます。


いいポスト。'function(){alert( "plop");で何が起こるか } 'いつ実行したのですか?GCされますか?
palig 2009

2
function(){alert( "plop"); }命令は関数を割り当てるだけですが、それを実行したり、変数にバインドしたりはしません。作成された関数はどの変数にもバインドされていないため、すぐにGCされます。
ビンセントロバート

このSOスレッドは、ここで話している範囲を超えていますが、JavaScript名前空間を分離する方法を説明し、自己呼び出し関数を使用する例も含まれています。
hotshot309

19

これが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!");

の本体で「var」で定義された変数make_fooが、によって返される各関数によって閉じられることは何の価値もありません。make_foo。これはクロージャであり、ある関数によって値に加えられた変更は別の関数からも見えることを意味します。

これにより、必要に応じて情報をカプセル化できます。

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

これは、Javaを除くほとんどすべてのプログラミング言語が機能する方法です。


8

あなたが示すコード、

(function (msg){alert(msg)});
('SO');

2つのステートメントで構成されます。1つ目は、関数オブジェクトを生成する式です(保存されていないため、ガベージコレクションされます)。2番目は、文字列を生成する式です。関数を文字列に適用するには、作成時に文字列を引数として関数に渡す必要があります(これも上に示しています)、または実際に関数を変数に格納して、次のことができるようにする必要があります。後で自由に適用してください。そのようです:

var f = (function (msg){alert(msg)});
f('SO');

匿名関数(ラムダ関数)を変数に格納することで、関数に名前を付けていることに注意してください。したがって、通常の関数を定義することもできます。

function f(msg) {alert(msg)};
f('SO');

7

以前のコメントの要約:

function() {
  alert("hello");
}();

変数に割り当てられていない場合、構文エラーが発生します。コードは関数ステートメント(または定義)として解析され、閉じ括弧が構文的に正しくなくなります。関数部分を括弧で囲むと、インタープリター(およびプログラマー)に、これが関数式(または呼び出し)であることを通知します。

(function() {
  alert("hello");
})();

これは自己呼び出し関数です。つまり、宣言された同じ行で呼び出しが行われるため、匿名で作成され、すぐに実行されます。この自己呼び出し関数は、引数のない関数を呼び出すためのよく知られた構文と、関数名の前後に括弧を追加して示されています(myFunction)();

ある良いSOディスカッションJavaScript関数の構文は次のとおり


3

この回答は質問に厳密に関連しているわけではありませんが、この種の構文機能は関数に固有のものではないことを知りたいと思うかもしれません。たとえば、次のようなことをいつでも実行できます。

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

関数を宣言すると同時に関数で実行できるもう1つのことは、関数に対してnew演算子を呼び出してオブジェクトを取得することです。以下は同等です。

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};

3

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

2
+1明確にするために小さなサンプルを追加しました:-)初めて読んだときは、4回読み直さなければなりませんでした。
xanatos

3

質問者の質問に対する私の理解は次のようなものです。

この魔法はどのように機能しますか:

(function(){}) ('input')   // Used in his example

私は間違っているかもしれません。ただし、人々が慣れ親しんでいる通常の習慣は次のとおりです。

(function(){}('input') )

その理由は、JavaScriptがAKAを括弧で括っているからです。 ()がステートメントを含むことができず、パーサーがfunctionキーワードに出会ったときに、それを関数宣言としてではなく関数式として解析することがわかっているためです。

ソース:ブログ投稿即時に呼び出される関数式(IIFE)


3

括弧なしの例:

void function (msg) { alert(msg); }
('SO');

(これはボイド、アファイクの唯一の実際の使用法です)

または

var a = function (msg) { alert(msg); }
('SO');

または

!function (msg) { alert(msg); }
('SO');

同様に動作します。これvoidにより、式が評価され、割り当てと強打が評価されます。最後のものはで動作する~+-deletetypeof、単項演算子の一部は(voidだけでなく、1です)。働いていないカウスである++--なぜなら変数の要件のため。

改行は不要です。


ie11での@Bergiのdelete動作。でも'use strict';。この作品、あまりにも:delete (3 + 4);
ニーナショルツ

おっと、私の間違い。" 2)Type(ref)がReferenceでない場合、trueを返します。 "解決できない実際の参照に対してのみエラーをスローします。
Bergi

1

これは、自己実行型の匿名関数です。ブラケットの最初のセットには実行される式が含まれ、ブラケットの2番目のセットにはそれらの式が実行されます。

(function () {
    return ( 10 + 20 );
})();

ピーター・ミショーは括弧の重要なペアの違いを議論しますます。

親名前空間から変数を隠そうとするときに便利な構成です。関数内のすべてのコードは、関数のプライベートスコープに含まれているため、関数の外部からまったくアクセスできず、真にプライベートになります。

見る:

  1. 閉鎖(コンピュータサイエンス)
  2. JavaScriptネームスペース
  3. Javascript括弧の重要なペア

0

別の視点

まず、無名関数を宣言できます。

var foo = function(msg){
 alert(msg);
}

次に、それを呼び出します:

foo ('Few');

そのためFOO =機能(MSG){警告(MSG);}あなたが交換できるようにFOOを通り:

function(msg){
 alert(msg);
} ('Few');

ただし、解析時に関数を宣言する構文エラーを回避するために、匿名関数全体を中括弧のペアで囲む必要があります。次に、

(function(msg){
 alert(msg);
}) ('Few');

このように、私にはわかりやすいです。


0

あなたがしたとき:

(function (msg){alert(msg)});
('SO');

('SO')セミコロンのために前に関数を終了しました。あなたが書くだけなら:

(function (msg){alert(msg)})
('SO');

それが動作します。

作業例:http : //jsfiddle.net/oliverni/dbVjg/


0

これが機能しない単純な理由;は、無名関数の終了を示すためではありません。これは()、関数呼び出しの終わりがなければ、関数呼び出しではないためです。あれは、

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 = 'help'がヘルプ関数を実行しない限り、関数呼び出しは最後にon がないと関数呼び出しではありません。setTimeoutとsetIntervalもこのタイプの関数呼び出しも許可すると思います。また、インタプリタがかっこを背後に追加して、「関数呼び出しはかっこなしの関数呼び出しではありません」に戻ると信じています。


これがなぜ多くの反対票を受け取ったのか理解できません。それは受け入れられる答えだと思いますか?:/
ダニエル・チャン

0
(function (msg){alert(msg)})
('SO');

これは、多くのJavaScriptフレームワークが使用するクロージャーとして無名関数を使用する一般的な方法です。

この関数は、コードのコンパイル時に自動的に呼び出されます。

;最初の行に配置した場合、コンパイラーはそれを2つの異なる行として扱いました。したがって、上記と同じ結果を得ることができません。

これは次のように書くこともできます:

(function (msg){alert(msg)}('SO'));

詳細については、JavaScript /無名関数をご覧ください。


私の知る限り、JavaScriptは「コンパイル」されません
Daniel Cheung

0
  1. 無名関数は、実行時に動的に宣言される関数です。これらは、通常の関数と同じように名前が付けられていないため、無名関数と呼ばれています。

    無名関数は、関数宣言の代わりに関数演算子を使用して宣言されます。関数演算子を使用して、式を置くことが有効な場所であればどこでも新しい関数を作成できます。たとえば、新しい関数を関数呼び出しのパラメーターとして宣言したり、別のオブジェクトのプロパティを割り当てたりできます。

    名前付き関数の典型的な例を次に示します。

    function flyToTheMoon(){alert( "Zoom!Zoom!Zoom!"); } flyToTheMoon(); これは、無名関数として作成された同じ例です。

    var flyToTheMoon = function(){alert( "Zoom!Zoom!Zoom!"); } flyToTheMoon();

    詳細はこちらをお読みください:

    http://helephant.com/2008/08/23/javascript-anonymous-functions/


0

IIFEは単に関数を区分化しmsg、グローバル名前空間を「汚染」しないように変数を非表示にします。実際には、10億ドルのウェブサイトを構築しているのでない限り、単純にして以下のようにします。

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;
}());

-1

匿名関数は、その場で関数を定義して、提供している入力からユーザーからの出力を生成するワンショット取引であることを意図しています。入力を提供しなかったことを除いて。代わりに、2行目( 'SO')に何かを書きました。-関数とは無関係の独立したステートメント。何を期待しましたか?:)


100%正解ではありません。これも無名関数であり、再利用することを意図しています:var foo = function() {};。それ以外はすべて問題ありません。
Felix Kling 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.