👀

関数代入時における括弧の有無による挙動の違い【個人学習まとめ】

に公開

今回の問題点

学習中に関数の動きを確認したくて、次のようなコードを書きました。

let function1 = () => ({ name: "太郎" });
let function2 = () => ({ name: "次郎", age: 20 });
function1 = function2;
console.log(function1);

コンソールの結果は次のような想定をしていました。

name: "次郎", age: 20

しかし、実際の結果は私の想定と異なりました。

[Function: function2]

はて?となったので今更ながら調べ、主に2つのポイントがあることと私の間違いに気が付きました...。

ポイント1 afunction11 = afunction2 の意味

今回のコードをもう一度確認してみます。

 let afunction1 = () => ({ name: "太郎" });
 let bfunction2 = () => ({ name: "次郎", age: 20 });
 afunction1 = bfunction2;
 console.log(afunction1);

まずfunction1 = function2;部分ですが、これはfunction1という変数にfunction2の関数本体を代入していることを意味します。
この代入により、function1には関数の実行結果ではなく、関数そのもの(() => ({ name: "次郎", age: 20 })) が代入されました。

ポイント2 console.log(function1) の意味

次にコンソール部分を見てみましょう。

 (省略)
 console.log(afunction1);

このコードはfunction1の中身をそのまま出力するコードです。
console.logで関数をそのまま出力する場合は、"[Function: 関数名]" の形式で表示し「これは関数ですよ」という情報を示してくれます。
今回の場合はfunction1にはfunction2が代入されているので、コンソールには"[Function: function2]"と表示されます。

ここまできたらコンソールの結果が[Function: function2]となったことは理解できますね。

私の間違い

では、私が間違っていたのはどこだったのか確認していきましょう。
それはlet function1 = () => ({ name: "太郎" });の挙動の理解が間違っていました。
私はこのコードを
function1にname: "太郎"というオブジェクトを代入している。
という認識をしていました。
正しくは、function1 に 関数を代入しているということです。

さらにこの間違いを深堀してみると、

  • アロー関数(() => {...})
  • 関数を呼び出すまでは中身が実行されない
    この2点をよく理解していなかったことが判明しました。

今回の例を使いながら、上記2点を再度学習しました。

アロー関数

構文:() => {...}
今回のコードlet function1 = () => ({ name: "太郎" });function1という引数無し関数を定義しているという意味になります。
JavaScriptのfunctionキーワードを使った次のコードと同等になります。

 function function1() {
   return { name: "太郎" };
 }

今回のアロー関数() => ({ name: "太郎" })では括弧をつかってオブジェクトを返しているため、オブジェクトが直接書かれているように見えました。
しかし、これは関数が実行された時に返す値を示しているだけであり、変数function1にオブジェクトを定義しているわけではありません。

関数を呼び出すまでは中身が実行されない

function1という変数は、代入した直後では関数の定義そのものを保持しています。
関数を実行しない限り、{ name: "太郎" }というオブジェクトは生成されません。

console.log(function1);  関数そのものが表示される
→ [Function: function1]
console.log(function1());  関数を実行し、オブジェクトが表示される
→ { name: '太郎' }

実際に想定していた結果を得るには?

私が当初想定していた結果をコンソールに出力してみましょう。
まずは私の想定をおさらいです。

name: "次郎", age: 20

これは関数の実行結果になるので、関数そのものを呼び出す必要があると分かりますね。

let afunction1 = () => ({ name: "太郎" });
let bfunction2 = () => ({ name: "次郎", age: 20 });
afunction1 = bfunction2;
console.log(afunction1());{ name: '次郎', age: 20 }

これでやりたかったことが実現できました。
JavaScriptは括弧の使い分けが難しい...と感じました。
今回は非常に簡単なコードで気が付くことができたので、この機会に1つ1つ確実に定着させて将来困らないようにしましょう。

Discussion