54190


JavaScriptにおいて、

[code]

    (function(){
     //...
    
    })();
    
[/code]

の書き方は、どのような意味なのでしょうか？

引用は、  
<http://d.hatena.ne.jp/babu_babu_baboo/20170109/1483925930>  
のコードです。


CC BY-SA 4.0
2019-04-15T08:41:16.467
54184
2019-04-15T13:22:26.010
12297
question
javascript
JavaScriptにおける、(function(){ //... })(); はどういう書き方ですか？


Immediately invoked function expression と呼ばれるもので、無名関数を定義した直後に実行する記法です。

例えば次のように書くと、コンソールに「 hello 」と出力されます。

[code]

    (function(a) {
      console.log(a); 
    })('hello');
    
[/code]

スコープを区切るためによく使われるかと思います。

参考:

  * <https://developer.mozilla.org/en-US/docs/Glossary/IIFE>
  * <https://en.wikipedia.org/wiki/Immediately_invoked_function_expression>
  * <https://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript>


CC BY-SA 4.0
2019-04-15T13:05:19.963
54189
2019-04-15T13:05:19.963
28632
54184
answer


構文的なことだけを言うと単なる関数呼び出しです。

[code]

    function someFuncName() {
        //...
    
    }
    someFuncName();
    
[/code]

なんて書くのとほぼ同じです。なぜ「ほぼ」がつくのかと言うと、`someFuncName`と言う名前の変数や関数がどこかですでに定義されていたり、使用されていたりすると意味が変わってしまうからだと思ってください。1回呼ばれたらそれで終わりの関数に、衝突の無いような名前を考えたりしたくないし、1回呼ばれたらもう2度と使わないと言うことを明示したいために、無名関数を作りそれをいきなり呼び出しているわけです。

* * *

ここまではわかっている人も多いんですが、ではなぜすぐに実行させる、1回しか使わないものをわざわざ関数として書くのでしょうか?

一つ良くある理由は、「グローバル環境(※)を汚したくないから」と言うものです。

(※)コンテキストと呼んだりもします。(ECMAなんかの公的規格の中でなんて呼ばれているかは失念しました、すいません。)ざっくりと「変数や関数定義を覚えておくための何か」を「環境」と呼んでいると思ってください。

例えば、1〜100までの合計値をある変数に代入したいとして、

[code]

    var sum = 0;
    for( var i = 1; i <= 100; ++i ) {
        sum += i;
    }
    
[/code]

と書くのと、

[code]

    var sum = (function() {
        var s = 0;
        for( var i = 1; i <= 100; ++i ) {
            s += i;
        }
        return s;
    })();
    
[/code]

と書くのはどう違うのかと言うと、上では`i`は例え`var`で変数宣言していたとしても、`i`はグローバル環境に定義された変数となり、もし他に変数`i`が使われていたとすると、なにか影響が出てしまうかもしれません。(この例は単純化されすぎていて、「`let`を使えば良いじゃん」と思う人も多いでしょうが、ちょっと複雑な計算をするときに、他にも一時変数が必要になることは多々あって、そう言うものが確実にグローバル環境に影響しないように宣言できるメリットはご理解いただけると思います。)

JavaScriptでは、関数呼び出しを実行すると、そういった一時変数等を格納するためのローカル環境が新たに作られ、関数内で変数宣言や(ネストされた)関数定義を行うと、そのローカル環境内に変数の実体や関数定義が保持されます。(例によって関数呼び出し単位ではなく、「ブロック」単位のローカル変数のことは置いてください。本質的には同じことです。)

したがって、上の後半のコードで、`i`や`s`を関数内で変数宣言しているわけですが、それらがグローバル変数と重なって何か困ったことが起きると言う心配は無いわけです。

そして、このように作られたローカル環境は、関数の実行が終わるときに(通常であれば)捨てられてしまい、ローカル変数の値も関数定義も消えてしまいます、通常は。

* * *

ですが、引用先の記事では、もうちょっと突っ込んだ意図を持って、無名関数の即時呼び出しを使っています。

それは「 **ローカル環境に結び付けられた関数オブジェクトを作成する** 」ためです。

何を言いたいのかわかりにくいかもしれません。引用先の記事のコードは複雑すぎるので、ちょっと単純化した例を作ってみます。

[code]

    var myFuncs = (function() {
        var value = 0;
    
        function getValue() {
            return value;
        }
    
        function increment() {
            ++value;
            return getValue();
        }
    
        return {'getValue': getValue, 'increment': increment};
    })();
    console.log(myFuncs.getValue);
    console.log(myFuncs.increment);
    
    console.log(myFuncs.getValue());
    console.log(myFuncs.increment());
    console.log(myFuncs.getValue());
[/code]

これを実行させてみると、`myFuncs.getValue`と`myFuncs.increment`が無名関数内で定義された関数オブジェクトを保持していることがわかると思います。

そして、その関数を呼び出している、3個目から5個目の`console.log`ですが、全く同じコードの`console.log(myFuncs.getValue());`が1回目は`0`と、`myFuncs.increment()`を呼び出した後の2回目は`1`と表示されるのがわかるはずです。

つまり普通なら関数呼び出しが終わったら消えてしまうはずのローカル変数(を含むローカル環境)が上記の関数オブジェクト内に保持されているのです。したがって関数オブジェクト`getValue`内で参照されている`value`は、そのローカル環境内で定義されたローカル変数であり、関数オブジェクト`increment`が参照する`value`も、同じローカル環境内の同じローカル変数なので、`increment`を実行した結果が、`getValue`にも反映されているわけです。

* * *

あなたの引用先の、最初の(function()
{...})();では、このようにしてローカル環境内の多数のローカル変数やローカル関数に依存する関数`create`を定義し、その定義でできた関数オブジェクトをグローバル環境の`create`に代入しています。

したがって、その`create`を実行する場合には、(通常なら消えちゃっているはずの)ローカル変数やローカル関数を参照することができます。

「クロージャー」と呼ばれるものがそういったローカル環境をキャプチャする、と言う性質を使った、ちょっと高度な利用方法で、そこまでの解説を求めていなかったのなら、少しわかりにくかったかもしれません。ざっくり斜め読みして「クロージャー」なんて用語に興味を引かれたらまた読み直してみてください。


CC BY-SA 4.0
2019-04-15T13:22:26.010
54190
2019-04-15T13:22:26.010
13972
54184
answer