JavaScript 即時起動関数の表現

要約: このチュートリアルでは、JavaScript の即時起動関数の表現(IIFE)について学習します。

TL;DR

JavaScript の即時起動関数の表現は、式として定義され、作成直後に実行される 関数 です。次のように、即時起動関数の表現を定義する構文を示します。

(function(){
    //...
})();
Code language: JavaScript (javascript)

IIFE の理由

関数 を定義すると、JavaScript エンジンは関数をグローバルオブジェクトに追加します。次の例を参照してください。

function add(a,b) {
    return a + b;
}Code language: JavaScript (javascript)

Web ブラウザでは、JavaScript エンジンは add() 関数を window グローバルオブジェクトに追加します。

console.log(window.add);Code language: JavaScript (javascript)

同様に、var キーワードを使用して関数の外側に 変数 を宣言した場合、JavaScript エンジンは変数もグローバルオブジェクトに追加します。

var counter = 10;
console.log(window.counter); // 10Code language: JavaScript (javascript)

グローバル変数と関数が多数ある場合、JavaScript エンジンはグローバルオブジェクトのスコープが失われるまで、それらに割り当てられたメモリだけを解放します。

その結果、スクリプトはメモリを非効率に使用する場合があります。さらに、グローバル変数と関数があると、名前の衝突が発生する可能性があります。

関数がグローバルオブジェクトを汚染しないようにする 1 つの方法は、即時起動関数の表現を使用することです。

JavaScript では、次の式を使用できます。

'This is a string';
(10+20);Code language: JavaScript (javascript)

これらの式には効果がなくとも、この構文は正しく機能します。関数は式として宣言することもでき、関数表現と呼ばれます。

let sum = function(a, b) {
    return a + b;
}Code language: JavaScript (javascript)

この構文では、代入演算子(=)の右側の部分は関数表現です。関数は式なので、括弧内にラップできます。

let sum = (function(a, b) {
    return a + b;
});Code language: JavaScript (javascript)

この例では、sum 変数は、2 つの引数を足す 匿名関数 として参照されます。

さらに、関数を作成直後に実行できます。

let sum = (function(a,b){
    return a + b;
})(10, 20);

console.log(sum);Code language: JavaScript (javascript)

この例では、sum 変数は関数呼び出しの結果を保持します。

関数は式として作成され、すぐに実行されるため、次の式を即時起動関数の表現(IIFE)と呼びます。

(function(a,b){
        return a + b;
})(10,20);Code language: JavaScript (javascript)

IIFE を定義するための一般的な構文を次に示します。

(function(){
    //...
})();
Code language: JavaScript (javascript)

矢印関数 を使用して IIFE を定義できることにも注意してください。

(() => {
    //...
})();Code language: JavaScript (javascript)

関数変数 を即時起動関数の表現内に配置することで、グローバルオブジェクトに対する汚染を回避できます。

(function() {
    var counter = 0;

    function add(a, b) {
        return a + b;
    }

    console.log(add(10,20)); // 30
}());
Code language: JavaScript (javascript)

名前付き IIFE

IIFE には名前を付けることができます。ただし、実行後に再び呼び出すことはできません。

(function namedIIFE() {
    //...
})();
Code language: JavaScript (javascript)

セミコロン(;)で始まる IIFE

時にセミコロン(;)で始まる IIFE を目にすることがあります。

;(function() {
/* */
})();Code language: JavaScript (javascript)

この構文では、2 つ以上の JavaScript ファイルが盲目的に単一のファイルに連結される場合に、文を終了するためにセミコロンが使用されます。

たとえば、IIFE を使用する lib1.jslib2.js という 2 つのファイルがある場合があります。

(function(){
    // ...
})()


(function(){
    // ...
})()
Code language: JavaScript (javascript)

コードバインダツールを使用して両方のファイルのコードを1つのファイルに連結する場合、セミコロン(;)がないと連結されたJavaScriptコードは構文エラーが発生します。

実稼働中のIIFE

以下の関数を備えたcalculator.jsというライブラリがあるものとします

function add(a, b) {
    return a + b;
}

function mutiply(a, b) {
    return a * b;
}Code language: JavaScript (javascript)

そして、HTMLドキュメントにcalculator.jsを読み込みます。

その後、別にもう1つのJavaScriptライブラリであるapp.jsを同じドキュメントに読み込む必要があると思います

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE</title>
</head>
<body>
  <script src="calculator.js"></script>
  <script src="app.js"></script>
</body>
</html>Code language: HTML, XML (xml)

app.jsにもadd()関数があります

function add() {
    return 'add';
}Code language: JavaScript (javascript)

HTMLドキュメントでadd()関数を使用すると、2つの数字の合計ではなく'add'文字列が返されます

let result = add(10, 20);
console.log(result); // 'add'Code language: JavaScript (javascript)

これは、app.jsadd()関数がcalculator.jsライブラリのadd()関数をオーバーライドするためです。

これを修正するには、calculator.jsで次のようにIIFEを適用できます

const calculator = (function () {
    function add(a, b) {
        return a + b;
    }

    function multiply(a, b) {
        return a * b;
    }
    return {
        add: add,
        multiply: multiply
    }
})();Code language: JavaScript (javascript)

IIFEは、add()multiply()関数を参照するaddメソッドとmultiplyメソッドを含むオブジェクトを返します。HTMLドキュメントでは、calculator.jsライブラリを次のように使用できます

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE</title>
</head>
<body>
  <script src="js/calculator.js"></script>
  <script src="js/app.js"></script>
  <script>
    let result = calculator.add(10, 20); // add in app.js
    console.log(result); // 30
    console.log(add()); // add in the app.js
  </script>
</body>
</html>Code language: HTML, XML (xml)

calculator.add()calculator.jsによってエクスポートされたadd()関数を呼び出し、add()関数への2番目の呼び出しはapp.jsadd()関数を参照します。

jQueryとIIFE

次のHTMLドキュメントはjQueryライブラリを使用します

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE - jQuery</title>
</head>
<body>
  <h1>jQuery Demo</h1>
  <script src="https://code.jquery.com/jquery-3.4.1.slim.js"
    integrity="sha256-BTlTdQO9/fascB1drekrDVkaKd9PkwBymMlHOiG+qLI=" crossorigin="anonymous"></script>
  <script>
    let counter = 1;
    $('h1').click(function () {
      $(this).text('jQuery Demo' + ' Clicked ' + counter++);
    });
  </script>
</body>
</html>Code language: HTML, XML (xml)

jQueryライブラリをインポートすると、$またはjQueryオブジェクトを介して多くの便利なjQuery関数が利用できます。内部的には、jQueryはIIFEを使用して機能を公開しています。

こうすることで、jQueryは1つのグローバル変数($)を使用するだけで、グローバルオブジェクトを汚染することなく多くの関数を公開できます。

次の例は、IIFE内でjQuery $オブジェクトを_に変更する方法を示しています

 (function (_) {
      let counter = 1;
      _('h1').click(function () {
        _(this).text('jQuery Demo' + ' Clicked ' + counter++);
      });
  })(jQuery);Code language: JavaScript (javascript)

この例では、jQueryオブジェクトをIIFEに渡して、代わりに_引数を使用しました。

このチュートリアルでは、JavaScriptのすぐに呼び出される関数式(IIFE)とその目的について学びました。

このチュートリアルは役に立ちましたか?