スプレッド/レスト - 3つのドットがすること
このトピックを終えると
...が「スプレッド(展開)」と「レスト(収集)」という2つの役割を果たすことを理解できます。
同じ記号、異なる役割
JavaScriptでは、...は位置によって役割が異なります。
- スプレッド: 配列やオブジェクトを「展開」します。
- レスト: 残りの値を「収集」します。
同じ...ですが、使用する場所によって反対の動作をします。
スプレッド:展開
配列を展開します。
javascript
const a = [1, 2, 3];
const b = [0, ...a, 4];
// [0, 1, 2, 3, 4]...aが配列aの要素を1つずつ取り出して並べます。配列をコピーするときにも使用します。
javascript
const original = [1, 2, 3];
const copy = [...original];オブジェクトも展開します。
javascript
const defaults = { theme: "light", lang: "ko" };
const userSettings = { lang: "en", fontSize: 14 };
const config = { ...defaults, ...userSettings };
// { theme: "light", lang: "en", fontSize: 14 }後続のオブジェクトが同じキーを上書きします。デフォルト設定にユーザー設定を結合するパターンです。
関数に配列を渡すときにも使用します。
javascript
const nums = [3, 1, 4, 1, 5];
Math.max(...nums); // 5レスト:収集
関数のパラメータで「残りのすべて」を配列として受け取ります。
javascript
function sum(first, ...rest) {
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
return rest.reduce((a, b) => a + b, first);
}
sum(1, 2, 3, 4, 5); // 15...restが最初の引数の後の残りをすべて配列に収集します。
分割代入でも使用します。
javascript
const [head, ...tail] = [1, 2, 3, 4];
// head: 1, tail: [2, 3, 4]
const { name, ...others } = { name: "Alice", age: 25, city: "Seoul" };
// name: "Alice", others: { age: 25, city: "Seoul" }特定のプロパティのみを除いて残りを別に収集する場合に便利です。
スプレッドとレストの区別法
javascript
// スプレッド — 「入れる側」で展開
const arr = [...other];
func(...args);
// レスト — 「受ける側」で収集
function func(...params) {}
const [a, ...rest] = arr;値を送る場所(代入の右側、関数呼び出し)ではスプレッド。 値を受け取る場所(代入の左側、関数宣言)ではレスト。
実務パターン:不変更新
Reactで状態を更新する際に、元のオブジェクトを直接変更してはいけません。スプレッドを使用して新しいオブジェクトを作成します。
javascript
const [user, setUser] = useState({ name: "Alice", age: 25 });
setUser({ ...user, age: 26 });配列に要素を追加する場合も:
javascript
const [items, setItems] = useState(["a", "b"]);
setItems([...items, "c"]); // 最後に追加
setItems(["z", ...items]); // 最初に追加元の配列/オブジェクトは変更せずに、新しいものを作成します。
重要なポイント
...は**送る場所でスプレッド(展開)、受ける場所でレスト(収集)**です。 スプレッドで配列/オブジェクトをコピーおよび結合でき、レストで残りの値を収集できます。 Reactの不変状態更新で最も一般的に使用されるパターンです。