関数は、まとまった処理に名前を付けて、何度でも呼べるようにするしくみです。
(n) が受け取るもの、return が返すものです。
書き方は3つある
notYet(1);
const notYet = (n) => n + 1;結果は同じです。違うのは書き方と、次の2点だけです。
| 定義より前で呼べる | this |
|
|---|---|---|
function 宣言 |
呼べる | 呼ばれ方で決まる |
関数式(const f = function) |
呼べない | 呼ばれ方で決まる |
アロー関数(const f = () =>) |
呼べない | 持たない |
定義より前で呼べるかどうか
function で書いた関数は、丸ごと先に読まれます。
const に入れた関数はそうなりません。
const wrong = (n) => { value: n };
console.log(wrong(1));同じ「関数」でも書き方で挙動が違います。 → ReferenceError: Cannot access 'x' before initialization
迷ったら、定義を使うところより上に書いてください。 そうすれば書き方に左右されません。
返さないと undefined
return が無い関数は undefined を返します。エラーにはなりません。
return はそこで関数を抜けます。あとの行は実行されません。
先に返して抜ける書き方は、入れ子を浅くできるのでよく使われます。
アロー関数の {} に注意
アロー関数は、{} を書くかどうかで意味が変わります。
const double = (n) => n * 2;
console.log(double);
console.log(double + 1);{}なし … その式の値がそのまま返る{}あり … ふつうの関数と同じ。returnが要る
{} を書いて return を忘れるのは、いちばん多い間違いです。
map() で undefined が並ぶのも同じ原因です。
→ Array.prototype.map()
オブジェクトを返すときは丸括弧
{ が関数の本体と読まれています。value: はラベルとして無視されます。
丸括弧で囲むと、オブジェクトとして読まれます。
=> ({ ... }) はそのまま覚えてしまうのが早いです。
名前を付ける
const に入れた関数にも、変数名から名前が付きます。
エラーの表示に出るので、名前があると原因を追いやすくなります。
その場で書いた関数には名前がありません(空文字)。 2行目が空いているのは、名前が空文字だからです。
どれを使うか
新しく書くならアロー関数が短くて済みます。 ただし次の場合は function を使ってください。
- オブジェクトのメソッドとして書く(
thisが要る) - 定義より前で呼びたい
アロー関数は this を持たないので、メソッドには向きません。
→ なぜ this は呼び方で変わるのか
よくある間違い
呼ばずに関数そのものを渡す
() を付けないと、関数そのものが値として扱われます。
文字列と足すと、コードがそのまま繋がります。
画面に関数の中身が出たら、() の付け忘れを疑ってください。
引数の数が合わなくても落ちない
多すぎても少なすぎてもエラーになりません。
足りない分は undefined になり、計算に使うと NaN です。
既定値を書いておくと防げます。 → 関数の引数 — 既定値・可変長・分割代入
まとめ
- 書き方は3つ。結果は同じで、違うのは「前で呼べるか」と「
this」 function宣言だけが定義より前で呼べるreturnが無ければundefined。エラーにはならない- アロー関数で
{}を書いたらreturnが要る - オブジェクトを返すなら
=> ({ ... }) - 引数の数が合わなくても落ちない
次に学ぶ
関数の中で作った変数がどこから見えるかを学びます。 そして「関数が、作られた場所の変数を覚えている」という性質(閉包)まで進みます。