スプレッドとレストで組み替える
このレッスンで分かること
- 同じキーがぶつかったら、後ろに書いたほうが残ります
...は置いた場所で、ばらまくか、まとめるかが変わります
使わない引数まで書かされる
呼び出すたびに変わるかもしれない値が増えてくると、引数を 1 つずつ足す設計が破綻します。
JavaScript
applyTheme("light", 16, 3, false);変えたいのが 3 番目だけでも、前の 2 つを書かされます。しかも false が何を意味するのか、呼び出し行を見ても分かりません。設定はオブジェクト 1 つで受け取り、足りないところを既定値で埋める形にします。
JavaScript
function applyTheme(custom = {}) {
const base = { theme: "light", fontSize: 16, columns: 2 };
return { ...base, ...custom };
}
console.log(applyTheme({ columns: 3 }));
// { theme: "light", fontSize: 16, columns: 3 }{ ...base, ...custom } は「base の中身をばらまき、その上に custom の中身をばらまく」という意味です。同じキーがぶつかったときは後に書いたほうが残ります。だから既定値を先、受け取った設定を後ろに置きます。
順番を逆にすると、いつでも既定値が勝つコードになります。指定したはずの設定が効かないという形で表面化するので、原因の特定に時間がかかります。既定値は先、と型で覚えてください。
|| で埋めると 0 が消える
既定値を埋めるだけなら custom.columns || 2 でもよさそうに見えます。ここに落とし穴があります。
| 書きかた | 0 を渡す | null を渡す | キーを渡さない |
|---|---|---|---|
{ ...base, ...custom } | 0 | null | 既定値 |
custom.columns || 2 | 2 | 2 | 2 |
custom.columns ?? 2 | 0 | 2 | 2 |
利用者が「0 でよい」と指定した意図を、|| は消してしまいます。空文字や false でも同じことが起きます。ばらまいて重ねるやりかたは値の真偽を見ないので、0 も false もそのまま採用されます。
ひとつ注意があります。重ねるやりかたはキーさえあれば、値が undefined でも上書きします。{ columns: undefined } を渡すと既定値は消えて undefined になります。呼び出し側で「指定しない」を表したいなら、そのキーを渡さないのが正解です。
残りをまとめる ...
... を値を作る側に書くとばらまき、受け取る側に書くとまとめるという逆向きの働きになります。後者をレストと呼びます。
JavaScript
function joinLabels(separator, ...items) {
return items.join(separator);
}
console.log(joinLabels(" / ", "HTML", "CSS")); // HTML / CSS
console.log(joinLabels(" / ")); // 空文字...items は「残りの引数を全部この配列に入れる」という指示です。1 つも渡されなければ空の配列になるので、undefined かどうかを調べなくても length や map をそのまま呼べます。決まりは 2 つで、必ず最後の引数であることと、1 つしか置けないことです。残りをまとめる、という意味を考えれば当然の制限です。
呼び出す側で配列をばらして渡したいときも ... を書きます。
JavaScript
const chosen = ["HTML", "CSS"];
console.log(joinLabels(" / ", ...chosen)); // HTML / CSS
console.log(joinLabels(" / ", chosen)); // HTML,CSS 配列 1 つとして渡っている下の行は items が [["HTML", "CSS"]] になっています。入れ子が 1 段深いことに気付かないと、結合の結果がおかしいという形で表面化します。
配列を 1 つの引数として受ける
追加の値がすでに配列なら、レストにせず配列のまま受け取れます。色の一覧をつなぐ例です。
JavaScript
function appendColors(base = [], extra = []) {
return [...base, ...extra];
}
console.log(appendColors(["赤"], ["青", "白"])); // ["赤", "青", "白"]演習では受け取り方の変換を補助処理に任せ、デフォルト引数とスプレッドを書きます。
よくある間違い
- 既定値を後ろに置く —
{ ...custom, ...base }と書くと、指定した設定が既定値で上書きされて消えます - レスト引数を前に置く —
function ng(...items, custom) {}は構文エラーです。残りをまとめる以上、後ろに何かを置くことはできません - 浅いコピーのまま中身を書き換える — 重ねて作ったオブジェクトの中の配列は、元の配列と同じものを指しています。
pushすると元まで増えるので、新しい配列を作って差し替えます
要件
- mergeViewOptions の第 1 引数 options の既定値を空オブジェクト、第 2 引数 extraTags の既定値を空配列にする
- defaults を先、options を後に置き、スプレッドで新しい設定オブジェクトを作る
- 設定の tags の後ろに extraTags をスプレッドでつないだ新しい配列を作る
- sort、order、limit、tags を持つ新しいオブジェクトを返す。limit の 0 は変えず、元の配列も変更しない
- 採点用の buildViewOptions は準備済みなので変更しない