Object.assign とは何か
Object.assign は「右側のオブジェクトの“自前の列挙可能なプロパティ”を左側(ターゲット)へコピーして上書きする」関数です。ここが重要です:コピーされるのは“文字列キーと Symbol キーのうち enumerable: true なもの”で、継承プロパティは対象外。右側の値が左側を“後勝ち”で上書きします。
const target = { a: 1 };
const source = { b: 2, a: 9 };
Object.assign(target, source);
console.log(target); // { a: 9, b: 2 }(右側が後勝ちで上書き)
JavaScript基本の使い方(上書き・追加・複数の統合)
右側が後勝ち(上書きのルール)
右から左へ順にコピーされ、同じキーは最後に現れた値で上書きされます。これが設定の“上書き”設計の要になります。
const base = { theme: "light", lang: "ja" };
const override1 = { theme: "dark" };
const override2 = { lang: "en" };
const out = Object.assign({}, base, override1, override2);
// { theme:"dark", lang:"en" }(右側が優先)
JavaScriptターゲットを“直接”変更する
第1引数(ターゲット)は直接書き換えられ、戻り値もそのターゲットです。共有状態では注意が必要です。
const state = { count: 0 };
const result = Object.assign(state, { count: 1 });
console.log(state === result); // true(同じオブジェクトが返る)
JavaScriptシャローコピー(浅いコピー)であることの理解
浅いコピーの挙動(入れ子は“参照共有”)
Object.assign は“1階層分の値”を複製します。入れ子のオブジェクトは参照がそのままコピーされます。
const orig = { user: { id: 1 }, tag: "x" };
const copy = Object.assign({}, orig); // 浅いコピー
copy.user.id = 999;
console.log(orig.user.id); // 999(内側は同じ参照)
JavaScript入れ子まで独立させたいなら、深いコピー(structuredClone など)を使うか、必要な階層で手動展開します。
const deepUpdated = Object.assign({}, orig, { user: Object.assign({}, orig.user, { id: 2 }) });
JavaScriptコピー対象の範囲(enumerable/own/Symbol)
何がコピーされ、何がされないか
- 自身が持つ enumerable: true のプロパティが対象。継承プロパティは無視されます。
- Symbol キーでも enumerable: true ならコピー対象です。
- non-enumerable(defineProperty で enumerable: false)はコピーされません。
const k = Symbol("secret");
const obj = {};
Object.defineProperty(obj, "hidden", { value: 1, enumerable: false });
obj[k] = 123;
obj.visible = 2;
const out = Object.assign({}, obj);
console.log(out); // { visible: 2, [Symbol(secret)]: 123 }
JavaScriptアクセサ(get/set)とプロパティ属性の注意点
getter は“呼び出されて値がコピーされる”
assign は“値のコピー”をします。プロパティディスクリプタ(get/set や writable など)は保存されません。
const source = {
get price() { return 100; }
};
const target = Object.assign({}, source);
console.log(target.price); // 100(値としてコピー。getterではなくなる)
JavaScript属性は引き継がれない
Object.defineProperty で設定した writable/enumerable/configurable はコピー先では既定の属性になります(値だけ移る)。属性ごと複製したい場合は defineProperty を使って自分で定義します。
例外とガード(安全に使う)
ターゲットが null/undefined は TypeError
第1引数が null/undefined だと例外になります。sources が null/undefined の場合は“無視される”仕様です。
// NG: Object.assign(null, { a: 1 }) // TypeError
Object.assign({}, null, { a: 1 }); // { a: 1 }(null は無視)
JavaScript非破壊で使う基本形(新インスタンスへ)
共有状態・React などでは、ターゲットに {} を渡して“新しいオブジェクト”へまとめるのが安全です。
const merged = Object.assign({}, base, patch);
JavaScript実務パターン(設定の既定値・差分反映・部分更新)
既定値を適用して上書き
既定値 → ユーザー設定 → さらに一時的な上書きの順で“後勝ち”にします。
const defaults = { timeout: 5000, retry: 2, theme: "light" };
const userCfg = { retry: 5 };
const runtime = { theme: "dark" };
const cfg = Object.assign({}, defaults, userCfg, runtime);
// { timeout:5000, retry:5, theme:"dark" }
JavaScript差分だけ反映(空オブジェクトに積む)
変更点だけを抽出してターゲットへ適用します。
function applyDiff(target, diff) {
return Object.assign(target, diff); // 直接反映(破壊的)
}
// 非破壊にしたいなら:
function mergeDiff(base, diff) {
return Object.assign({}, base, diff);
}
JavaScript入れ子の部分更新(シャロー+一点深掘り)
浅いコピー+更新したい階層をもう一段 assign します。
const state = { prefs: { theme: "light", lang: "ja" }, user: { name: "A" } };
const updated = Object.assign({}, state, {
prefs: Object.assign({}, state.prefs, { theme: "dark" })
});
// prefs.theme だけ非破壊更新
JavaScript配列やクラスインスタンスでの注意(性質の違い)
配列は“インデックスのプロパティ”を上書き
配列にも使えますが、意図が伝わりづらいので基本は配列専用メソッドを使いましょう。
const a = [10, 20];
Object.assign(a, { 1: 99, 2: 77 }); // インデックス1と2を上書き/追加
console.log(a); // [10, 99, 77]
JavaScriptクラスインスタンスへコピー
インスタンスの自前 enumerable プロパティには有効ですが、メソッドやプロトタイプの振る舞いは“コピーされません”。
class User { constructor() { this.name = "A"; } greet() {} }
const u = new User();
const patch = { name: "B", role: "admin" };
Object.assign(u, patch); // プロパティだけ追加/更新(メソッドはそのまま)
JavaScriptObject.assign とスプレッド構文の使い分け
スプレッドは“書きやすい非破壊合成”
多くの場面で { ...a, ...b } の方が短く読みやすいです。属性や getter の扱いは assign と同様に“値コピー”です。
const merged = { ...defaults, ...userCfg, ...runtime };
JavaScriptassign の利点
- 実行時に動的な数だけ連結できる(
Object.assign({}, ...sources))。 - 参照で同じオブジェクトを返すため、意図的な“破壊的更新”を明示できる。
まとめ
Object.assign は「右側の自前・列挙可能なプロパティを左側へ“浅く”コピーする」ための基本関数です。右側が後勝ちで上書きされ、ターゲットは“直接変更”される点が最重要。入れ子は参照共有になるため、必要な階層で再度 assign(または structuredClone)して非破壊更新を設計する。コピー対象は enumerable な文字列キーと Symbol キーで、getter は値がコピーされ属性は保持されない。ターゲットの null/undefined は例外になること、sources の null/undefined は無視されることを押さえ、設定の既定値適用・差分反映・部分更新で実務的に使いこなしましょう。
