i_amaiの雑記

お金稼ぎが目的の、クソつまんないブログです

変数に対する関数の代入

こんにちは!皆さん、JavaScript書いてますか。初心者プログラマのi_amaiです。

もともとN予備校のプログラミング入門講座経由でNode.jsをちょこちょこ書いていたんですが、少し規模の大きなアプリを作ろうとしたときに現在の理解レベルでは不安があったため、再度入門というかたちでjsPrimerを読んでいるところです。

今回の日記はJavaScriptの勉強中にその仕様で一日ほどハマってしまったため、その備忘録となります。

問題

下記のJavaScriptコードを御覧ください。

function f () {
  return 0;
}

const a = f();

const b = f;

2つの変数abの違いを簡潔に説明してください。

解答

function f () {
  return 0;
}

const a = f();

const b = f;

console.log(typeof a);  // => number
console.log(typeof b);  // => function

変数aには関数fの実行された返り値である0が代入されます。

変数bには関数fそのものが(実行されずに)代入されます。

私がハマったのは以下のコード。

function f () {
  let x = 0;
  console.log(x);
  return function i () {
    return x += 1;
  }
}

const a = f();  // 0 undefined
a();            // 1
a();            // 2

クロージャの学習で、jsPrimerを参考に「関数を返す関数」を書きました。

変数aに関数fを代入したときに、初回のlet x = 0;console.log(x);が処理されるのは、まあ分かります。

その次の行で変数aを関数として呼び出した時、let x = 0;console.log(x);が処理されず、xがインクリメントされるのはなぜかが分かりませんでした。

なんのことはなくて、fの後の()の効果により、変数aには関数fを実行した返り値である関数iが代入されているのです。

関数f自体は変数aへの代入時の1回しか実行されません。

これを防ぐ、つまり関数f自体を変数に代入したい場合は、

const a = f;

とする必要があります。

このように、JavaScriptでは関数に対する()のある/なしが処理の違いを生むのです。

言語による違い

さてこの仕様、他の言語ではどうなのでしょう? 自分のPCに入っているいくつかの言語で試してみました(間違っていたら教えてください)。

JavaScriptと同じ仕様

()あり:関数を実行し、その返り値を代入する

()なし:関数そのものを代入

括弧のあるなしに関わらず関数を実行し、その返り値を代入

その他

VB.NETについては、Visual Studio上で関数を代入する際に()が自動補完され、()なしを試すことができませんでした。()ありの場合は当然、JavaScriptの仕様と同様でした。

まとめ

言語によって処理に違いがあるのは面白いですね。もうちょっと研究すると色々捗るかもしれません。

私はもう疲れました…

それでは今日はこの辺で。