JavascriptのIIFE(即時実行関数式)とは
IIFE(即時実行関数式)とは
■定義
IIFEとは「Immediately Invoked Function Expression」の略であり、日本語で「即時実行関数式」と訳されます。その名の通り、定義されたタイミングですぐに実行されるJavascript関数のことを指します。
通常関数は、定義された後に別途呼び出される必要がありますがIIFE(即時実行関数式)は宣言されたタイミングで自動的に実行されるという特徴があります。
■基本的な構文
基本的に以下のような構文で定義されます。
(function() {
// 実行したいコードを記述
})();
■背景
2010年11月15日にBen Almanのブログにて紹介されました。
上記のブログでは具体的な定義や用法、またIIFEを使用し関数内の状態を保持することによって実現できることの一例が紹介されています。
例えばボタンをクリックすると "I am link #[番号]" というログが出るコードを書いたとします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IIFE Test</title>
</head>
<body>
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
<a href="#">Link 4</a>
<a href="#">Link 5</a>
<script>
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {
elems[i].addEventListener('click', function(e) {
e.preventDefault();
console.log('I am link #' + i);
}, false);
}
</script>
</body>
</html>
しかし上記のコードだと、どのボタンをクリックしても全て "I am link #5" というログが出てしまいます。なぜなら変数iの状態を保存できておらず、console.logのコードが実行時には for文が全て実行完了しており i = 5になっているからです。
ここでIIFE(即時実行関数式)を使ってみましょう。IIFEを使った以下のコードを実行すると、正しく "I am link #2" といったログが出力されます。なぜなら変数iの状態が関数内に保存されるからです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IIFE Test</title>
</head>
<body>
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
<a href="#">Link 4</a>
<a href="#">Link 5</a>
<script>
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {
(function(i) {
elems[i].addEventListener('click', function(e) {
e.preventDefault();
console.log('I am link #' + i);
}, false);
})(i);
}
</script>
</body>
</html>
■発展: 即時実行アロー関数
IIFEを記述する際に、アロー関数を使って記述することもできます。
(() => {
// 実行したいコードを記述
})();
利点
一番の利点はグローバル名前空間の汚染を避けることができることです。IIFEで定義された変数は、通常の関数と同じように関数のスコープ内だけで使用可能です。
予期しないバグや競合を防いだり、不要になったメモリが解放されやすくなるため、メモリ管理が効率的になります。
■ES6以降
ES6以前にこの問題を解決する場合にはこのIIFEパターンを使っていましたが、それ以降は let を使うとより簡単に書くことができるようになりました。
for (let i = 0; i < elems.length; i++) {
elems[i].addEventListener('click', function(e) {
e.preventDefault();
console.log('I am link #' + i);
}, false);
}