☆この記事でわかること☆
- JavaScriptにおいて「関数」は特別な構文ではなく値の一種であること
- 関数宣言と関数式の違い
-
edamameとedamame()の決定的な違い(カッコの有無) - 初心者が絶対にハマる「なんで動かないんだ?」の鉄板パターン
はじめに
プログラミング学習をしていると「関数」って当たり前に使いますよね。
その中でJavaScriptにおける関数を
今回学んで「ほえー!」となったのは、
JavaScriptにおいて関数は"魔法の言語構造"ではなく、特別な種類の"値"である
ということです。この視点を持つと、カッコの有無でコードの挙動が
ガラッと変わる理由が分かってきます。
関数は「値」である
まずは普通の関数宣言から。
function edamame() {
alert( "Hello" );
}
これとは別に、関数式と呼ばれる別の書き方があります。
let edamame = function() {
alert( "Ho" );
};
この関数式を見ると、関数が他の任意の値と同じように
明示的に変数へ代入されているのがわかります。
つまり、どんな書き方で定義されても、関数は単に変数 edamame
に格納される「値」なのです。
カッコを付けないと実行されない
ここが第一のポイントです。
function edamame() {
alert( "Hello" );
}
alert( edamame ); // 関数のコードそのものが表示される
最後の行、edamame の後にカッコがないため、
関数は実行されません。
かわりに、関数の中身(ソースコードの文字列表現)が表示されます。
JSでは関数は「値」なので、他のタイプの値と同じように扱えるわけですね。
edamame() のように呼び出せる点で特別ではありますが、あくまで値です。
関数はコピーできる
値なので、当然コピーもできます。
function edamame() { // (1) 作成
alert( "Hello" );
}
let func = edamame; // (2) コピー(カッコ無し!)
func(); // Hello と表示 // (3) コピーの実行 → 動く!
edamame(); // Hello と表示 // これも動く!
何が起きているか、順を追って見てみましょう。
-
(1) 関数宣言で関数を生成し、変数名
edamameに格納 -
(2) それを変数
funcにコピー。ここでedamameの後に
カッコがない点が超重要 -
(3) これで
edamame()でもfunc()でも呼び出せる
もし (2) でカッコを付けて let func = edamame();
と書いてしまうと、話が変わります。
それは edamame 関数自身ではなく、edamame を呼び出した結果を
func に書き込むことになります。
edamame と edamame() の違い ~レシピの例え~
この違いを、料理のレシピで例えてみます。
-
edamame… 「関数そのもの」を指す。 レシピが書かれた紙そのもの -
edamame()… 「関数を実行して、その結果をちょうだい」という意味。
レシピ通りに料理して、出来上がった料理をもらうまで
カッコは「実行してね」という命令なんです。
コードで確認してみます。
function edamame() { // (1) 関数を作成。変数 edamame に「関数そのもの」が格納
alert("Ho");
return 42; // 実行されると 42 を返す
}
let a = edamame; // (2) カッコ無し → 関数そのものを a にコピー
// この時点では alert("Ho") は実行されない!(まだ料理してない)
let b = edamame(); // (3) カッコ有り → その場で edamame を実行
// alert("Ho") のポップアップが出て、返り値 42 が b に入る
// ここから呼び出し ━━━━━━━━━━━━━
edamame(); // 元の関数を実行 → alert("Ho") が出て、42を返す
a(); // a は関数そのもの → 実行できる。alert("Ho") が出て、42を返す
b(); // エラー! b is not a function → b は数字の 42 なので実行できない
ここで a の中身は関数、b の中身は 42 という数字。まったくの別モノです。
初心者ホイホイな罠
let func = edamame() とカッコを付けて書くと、
その場で edamame が実行されます。
alert("Ho") がその瞬間に発動し、func には返り値(return した値)が入ります。
そして、return が無い関数だと func には undefined
が入るという罠が待っています。
その状態で func() と呼び出そうものなら…
function edamame2() {
alert("実行されました");
// return が無い
}
let x = edamame2(); // alert が出て、x には undefined が入る
x(); // エラー! x is not a function
「関数を代入したはずなのに、なんで動かないんだ?」となるわけです。
原因は、代入した瞬間に実行されてしまい、
中身が関数ではなく返り値(or undefined)に化けていたから。
初心者が踏み抜く鉄板パターンらしいので、要注意です。
まとめ
- JavaScriptの関数は「魔法」ではなく、変数に格納できる"値"
-
edamameは「関数そのもの」、edamame()は「実行して結果をもらう」 - カッコは「実行してね」の命令
- カッコ付きで代入すると、その場で実行され、
返り値(無ければundefined)が入る →is not a functionエラーの温床
やって良かったこと🌟
func = edamame と func = edamame() の違いを、
レシピの紙 vs 出来上がった料理で例えられるようになったのがだいぶ収穫です。
これからも学んだことを記事化していきます。
ここまで読んでいただきありがとうございました!
