Object.assign()とスプレッド構文は何が違うのか
どちらもオブジェクトのプロパティをコピー・結合できます。大きな違いは、Object.assign()が第1引数のtargetへ値を適用するのに対し、スプレッド構文は新しいオブジェクトを作る書き方として利用する点です。
たとえば、既存のオブジェクトへ設定を反映するならObject.assign()、元の値を残したまま更新後のオブジェクトを作るならスプレッド構文、というように考えると整理しやすくなります。
Object.assign()の基本的な使い方
基本構文はObject.assign(target, ...sources)です。sourceの列挙可能な自身のプロパティがtargetへコピーされ、同じプロパティ名がある場合は後から指定した値で上書きされます。
const defaults = { theme: "light", pageSize: 20 };
const options = { pageSize: 50 };
const settings = Object.assign(defaults, options);
console.log(settings);
// 期待される結果: { theme: "light", pageSize: 50 }
console.log(defaults);
// 期待される結果: { theme: "light", pageSize: 50 }この例では、defaultsをtargetに指定しているため、defaults自体が変更されます。元のオブジェクトを変更したくない場合は、空のオブジェクトをtargetに指定します。
const user = { name: "Aki", role: "user" };
const updates = { role: "admin" };
const updatedUser = Object.assign({}, user, updates);
console.log(updatedUser);
// 期待される結果: { name: "Aki", role: "admin" }
console.log(user);
// 期待される結果: { name: "Aki", role: "user" }スプレッド構文の基本的な使い方
オブジェクトのスプレッド構文は、{ ...source }のように記述します。プロパティを展開して、新しいオブジェクトを作成できます。複数のオブジェクトを展開した場合は、後に書いたオブジェクトの値が優先されます。
const defaults = { theme: "light", pageSize: 20 };
const options = { pageSize: 50 };
const settings = { ...defaults, ...options };
console.log(settings);
// 期待される結果: { theme: "light", pageSize: 50 }
console.log(defaults);
// 期待される結果: { theme: "light", pageSize: 20 }状態更新や関数の引数処理など、元の値を直接変更せずに一部のプロパティだけを更新したい場面で使いやすい書き方です。
Object.assign()とスプレッド構文を比較する
| 比較項目 | Object.assign() | スプレッド構文 |
|---|---|---|
| 基本構文 | Object.assign(target, source) | { …source } |
| コピー先 | 指定したtarget | 新しく作るオブジェクト |
| 元オブジェクトへの影響 | targetに指定すると変更される | 通常は元オブジェクトを変更しない |
| 代表的な用途 | 既存のtargetへ値を適用する | コピーや更新後の値を作る |
const user = { name: "Aki", role: "user" };
const updates = { role: "admin" };
const byAssign = Object.assign({}, user, updates);
const bySpread = { ...user, ...updates };
console.log(byAssign);
// 期待される結果: { name: "Aki", role: "admin" }
console.log(bySpread);
// 期待される結果: { name: "Aki", role: "admin" }通常のプレーンオブジェクトを単純に結合する場合は同じ結果になることがあります。ただし、特殊なオブジェクトやアクセサープロパティなどでは処理の仕組みが異なるため、常に機械的に置き換えられるとは限りません。
共通する注意点:コピーは基本的に浅いコピー
Object.assign()とオブジェクトのスプレッド構文は、トップレベルのプロパティをコピーします。しかし、ネストしたオブジェクトや配列は参照が共有されるため、内部の値まで独立して複製されるわけではありません。
const user = {
name: "Aki",
preferences: { theme: "light" }
};
const copiedUser = { ...user };
copiedUser.preferences.theme = "dark";
console.log(user.preferences.theme);
// 期待される結果: "dark"
// preferencesは元のuserとcopiedUserで同じ参照を共有しているため複雑なデータを完全に独立させたい場合は、データ型や実行環境に応じて深いコピーの方法を検討してください。単純な設定値の結合と、データ全体の複製は分けて考えることが大切です。
開発現場での使い分け
- 元のオブジェクトを変更せず、新しい値を作ることを明示したい場合はスプレッド構文を使う。
- 既存のtargetへ複数の値をまとめて適用する処理ではObject.assign()を使う。
- どちらを選ぶ場合も、後に指定・記述したプロパティが上書きする順序を確認する。
- チームのコーディング規約や既存コードに合わせ、同じ目的の処理では記法を統一する。