JavaScript の即時関数 (immediate function) の書き方を調べてしまいます

即時関数の書き方は (function () { /* ... */ })() だったか、 (function () { /* ... */ }()) だったか、調べてしまうので、書いておきます。

環境

  • eslint: 4.18.1
  • eslint-config-standard: 11.0.0
  • eslint-plugin-standard: 3.0.1
  • babel-cli: 6.26.0
  • babel-preset-env: 1.6.1

JSLint

JSLint で次のコードをチェックしてみました。

"use strict";
(function () {
    console.log("message.");
})();

次のようなエラーになりました。

Wrap an immediate function invocation in parentheses to assist the reader in understanding that the expression is the result of a function, and not the function itself.

})();

JSLint: The JavaScript Code Quality Tool

関数の結果であることを明確にするために呼び出し自体をかっこで囲むように言っているようです。

次のように修正してチェックしてみました。

"use strict";
(function () {
    console.log("message.");
}());

エラーがなくなりました。

JSLint では (function () { /* ... */ }()); のパターンになるようです。

おそらく、わたしが最初に即時関数のパターンを覚えたのは、こちらだったと思います。 JSLint では、一方の書き方しかチェックが通らないことだけは覚えていました。

ESLint

ESLint でチェックしてみます。

.eslintrc の設定は次の通りです。

module.exports = {
    "extends": "standard"
}

次のコードをチェックしてみます。

// immediate.js
'use strict';
(function () {
  console.log('message.')
})()

チェックします。

$ eslint immediate.js
$

エラーが出力されずに、プロンプトが戻ってきました。

次に、次のコードをチェックしてみます。

// immediate.js
'use strict';
(function () {
  console.log('message.')
}())

チェックします。

$ eslint immediate.js
$

こちらもエラーが出力されずに、プロンプトが戻ってきました。

ESLint では (function () { /* ... */ })(); のパターンも (function () { /* ... */ }()); のパターンも許可しているようです。

Babel

Babel でも確認してみます。

.babelrc の設定は次の通りです。

{
  "presets": ["env"]
}

次のコードをトランスパイルしてみます。

// immediate.js
(() => {
  console.log('message')
})()

トランスパイルします。

$ babel immediate.js
'use strict';

(function () {
  console.log('message');
})();

トランスパイルされたものも (function () { /* ... */ })(); のパターンになっています。

次に、次のコードをトランスパイルしてみます。

// immediate.js
(() => {
  console.log('message')
}())

トランスパイルします。

$ babel immediate.js
SyntaxError: immediate.js: Unexpected token, expected , (3:1)
  1 | (() => {
  2 |   console.log('message')
> 3 | }())
    |  ^
  4 |

エラーになりました。 関数呼び出しの () がエラーだと言っているようです。

Babel は (function () { /* ... */ })(); のパターンになるようです。

JSLint と ESLint のトレンド

終わり

JSLint は昔の話。 ということで、 (function () { /* ... */ })(); の書き方にしようかな、と思っています。

31 March 2018 追記

当時、読んだ本を引用しておきます。

4.5 即時関数

即時関数パターンは、関数を定義したすぐにその関数を実行するための構文です。

(function () {
  alert('watch out');
}());

このパターンは本質的には関数式にすぎませんが、関数を作成した直後に実行されます。

即時関数 (immediate function) という用語は ECMAScript 標準では定義されていませんが、このパターンを説明するのに便利です。

このパターンは以下の部品で構成されます。

  • 関数式を使って関数を定義する(関数宣言は使えません)。
  • 最後に一対の括弧を付加する。これによって関数が即座に実行されます。
  • 関数全体を括弧で囲む(関数を変数に代入しないときだけこれが必要です)。

次の構文(最後の括弧の位置に注意してください)もよく使われますが、 JSLint は最初の構文を推奨します。

(function () {
  alert('watch out');
})();

…略…

4.5.2 即時関数からの戻り値

関数を囲む括弧を省略しても同じ結果が得られます。 即時関数の戻り値を変数に代入するとき括弧は必要ありません。 最初の括弧を省略した書き方は次のようになります。

var result = function () {
  return 2 + 3;
}();

この構文は簡潔ですが、誤読される可能性があります。 関数の最後にある () を見落としてしまうと、 result が関数を指していると誤読されるかもしれません。 実際には result は即時関数の戻り値、この場合は数値の 4 を指しています。

JavaScriptパターン ―優れたアプリケーションのための作法 | Stoyan Stefanov, 豊福 剛 |本 | 通販 | Amazon

誤読される可能性があるそうです。