Object.assign とは何か
Object.assign は、複数のオブジェクトを「左から右へ」順番にコピーして、1つのオブジェクトにまとめるための ES6 のメソッドです。
一言でいうと、「プロパティを上書きしながらマージするコピー機」です。
基本の形はこうです。
Object.assign(コピー先, コピー元1, コピー元2, ...);
JavaScriptコピー先オブジェクトに、コピー元オブジェクトのプロパティが「上書きしながら」追加されます。
ここが重要です:
- コピー先そのものが「書き換えられる」
- 同じキーがあった場合は、「後ろに書いたほう」が勝つ(上書きされる)
一番基本の使い方と「上書きのルール」
単純なマージ(結合)の例
const target = { a: 1 };
const source = { b: 2 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 2 }
console.log(source); // { b: 2 }(source はそのまま)
JavaScripttarget に source のプロパティがコピーされ、target 自体が変化します。Object.assign の戻り値も target です。
const result = Object.assign(target, source);
console.log(result === target); // true
JavaScriptつまり、Object.assign は「戻り値として返すオブジェクト」と「第1引数のオブジェクト」が同じものになります。
同じキーがあった場合(上書き順序)
const target = { a: 1, x: 10 };
const source1 = { b: 2, x: 20 };
const source2 = { c: 3, x: 30 };
const result = Object.assign(target, source1, source2);
console.log(result); // { a: 1, x: 30, b: 2, c: 3 }
JavaScriptここが重要です:
xは target にも source1 にも source2 にもある- 最終的には「一番右の source2 の x = 30」が採用される
- 後ろに書いたものほど「強い」
「デフォルト設定 → 上書き用の設定」という順番で並べると、意図どおりのマージになりやすいです。
「元を壊さないコピー」としての Object.assign
空オブジェクト {} をコピー先にすれば「新しいオブジェクト」を作れる
Object.assign は第1引数(コピー先)を書き換えますが、コピー先に「空オブジェクト {}」を渡せば、
元のオブジェクトは壊さずに「中身をコピーした新しいオブジェクト」を作れます。
const original = { a: 1, b: 2 };
// 空オブジェクトをコピー先にする
const copy = Object.assign({}, original);
copy.a = 99;
console.log(original); // { a: 1, b: 2 }
console.log(copy); // { a: 99, b: 2 }
JavaScriptここが重要です:
Object.assign(original, ...)と書くと original 自体が変わる(破壊的)Object.assign({}, original, ...)と書くと「新しいオブジェクト」を返してくれる(非破壊)
現在は { ...original } というスプレッド構文を使うことが多いですが、
考え方は Object.assign({}, original) とほぼ同じです。
複数のオブジェクトをまとめてコピーする
const base = { a: 1 };
const extra = { b: 2 };
const override = { a: 9 };
// base を元にしつつ、extra を足し、最後に override で上書き
const merged = Object.assign({}, base, extra, override);
console.log(merged); // { a: 9, b: 2 }
console.log(base); // { a: 1 }(元はそのまま)
JavaScript「浅いコピー」であること(ネストは共有される)
浅いコピーとは何か
Object.assign は「浅いコピー(shallow copy)」です。
これは、「一段目のプロパティだけ」を新しいオブジェクトにコピーし、
その中にあるオブジェクトや配列自体は「同じもの(参照)」を共有する、という意味です。
const original = {
a: 1,
nested: { x: 10 }
};
const copy = Object.assign({}, original);
// ネストしたオブジェクトの中身を書き換える
copy.nested.x = 99;
console.log(original.nested.x); // 99
console.log(copy.nested.x); // 99
console.log(original === copy); // false(外側は別)
console.log(original.nested === copy.nested); // true(内側は同じ)
JavaScriptここが重要です:
Object.assignは「外側のオブジェクト」を別にするだけ- 「中のオブジェクト」は同じものを指している(から、片方を変えるともう片方も変わる)
完全に独立したコピー(ディープコピー)が必要な場合は、Object.assign だけでは足りません。
最初のうちは「浅いコピー」という言葉と、この挙動だけ押さえておけば十分です。
よくある使いどころ(実務のイメージ)
デフォルト設定とユーザー設定のマージ
よくあるパターンは、「デフォルト設定」と「ユーザーからの設定」をマージして、
最終的な設定オブジェクトを作るケースです。
const defaultOptions = {
method: "GET",
timeout: 3000,
cache: "no-cache"
};
function makeOptions(userOptions) {
return Object.assign({}, defaultOptions, userOptions);
}
const opts = makeOptions({ timeout: 5000, method: "POST" });
console.log(opts);
// { method: "POST", timeout: 5000, cache: "no-cache" }
console.log(defaultOptions); // 元は変わらない
JavaScriptここが重要です:
- 左側(defaultOptions)の値が基本になる
- 右側(userOptions)の値で、同じキーがあれば上書きされる
- コピー先が
{}なので、defaultOptions 自体は壊れない
既存のオブジェクトを「拡張」する
既にあるオブジェクトに、追加情報を後から付け足すこともできます。
const user = { id: 1, name: "Alice" };
const extra = { role: "admin", active: true };
Object.assign(user, extra);
console.log(user);
// { id: 1, name: "Alice", role: "admin", active: true }
JavaScriptただし、この書き方は user 自体を書き換えてしまうので、
「元を絶対に変えたくない」場面では向きません。
「意図的に拡張したい」場合にだけ使うようにしましょう。
Object.assign とスプレッド構文の違い
ES6 には { ...obj } というスプレッド構文もあります。
これと Object.assign は、できることがかなり似ています。
よく使うパターン比較
コピーだけならこうなります。
const original = { a: 1, b: 2 };
// Object.assign
const copy1 = Object.assign({}, original);
// スプレッド
const copy2 = { ...original };
JavaScriptマージ(結合)ならこうです。
const a = { x: 1 };
const b = { y: 2 };
// Object.assign
const merged1 = Object.assign({}, a, b);
// スプレッド
const merged2 = { ...a, ...b };
JavaScriptどちらも結果は同じです。
ここが重要です:
- ES5 時代から存在するのが
Object.assign - ES6 以降の「新しい書き方」として好まれるのがスプレッド
{ ...obj }
新しくコードを書くときは、読みやすさの観点からスプレッドを使うことが増えていますが、Object.assign も古いコードやライブラリの中で普通に出てくるので、
「何をしているか」は理解できるようになっておくと安心です。
注意すべきポイント(重要部分の深掘り)
コピー先(第1引数)は必ず「書き換えられる」
const target = { a: 1 };
const source = { b: 2 };
const result = Object.assign(target, source);
console.log(target); // { a: 1, b: 2 }
console.log(result); // { a: 1, b: 2 }(target と同じ)
JavaScriptここが重要です:
Object.assignは「第1引数を変更する関数」- 戻り値も第1引数と同じオブジェクト
第1引数を「新しいオブジェクトにしたい」のか、「既存オブジェクトに上書きしたい」のか、
意図をはっきりさせてから使う必要があります。
継承されたプロパティはコピーしない(自分のプロパティだけ)
Object.assign は、「オブジェクト自身の“列挙可能なプロパティ”」だけをコピーします。
プロトタイプチェーン上のプロパティ(一種の“継承されたプロパティ”)はコピーされません。
初心者向けには、
「普通に {} で作ったオブジェクト同士なら、素直に期待どおりコピーされる」
くらいの理解で十分です。
null / undefined をコピー元にするときは無視される
コピー元として null や undefined を渡すと、無視されます(エラーにはならない)。
const target = { a: 1 };
Object.assign(target, null, { b: 2 }, undefined);
console.log(target); // { a: 1, b: 2 }
JavaScript例題で理解を固める
// 1) 単純なマージ
const t1 = { a: 1 };
const s1 = { b: 2 };
Object.assign(t1, s1);
console.log(t1); // { a: 1, b: 2 }
// 2) 複数マージと上書き
const t2 = { x: 0 };
const s2 = { x: 1, y: 2 };
const s3 = { x: 3 };
const r2 = Object.assign({}, t2, s2, s3);
console.log(r2); // { x: 3, y: 2 }
// 3) デフォルトオプション+ユーザーオプション
const defaultCfg = { theme: "light", fontSize: 14 };
const userCfg = { fontSize: 16 };
const cfg = Object.assign({}, defaultCfg, userCfg);
console.log(cfg); // { theme: "light", fontSize: 16 }
// 4) 浅いコピーの確認
const state = { user: { name: "Alice" }, count: 0 };
const stateCopy = Object.assign({}, state);
stateCopy.user.name = "Bob";
console.log(state.user.name); // "Bob"(ネストは共有)
console.log(stateCopy.user.name); // "Bob"
// 5) 既存オブジェクトを拡張(破壊的)
const user = { id: 1, name: "Alice" };
Object.assign(user, { role: "admin" });
console.log(user); // { id: 1, name: "Alice", role: "admin" }
JavaScriptまとめ
Object.assign の核心は、
「第1引数のオブジェクトに、右側のオブジェクトのプロパティを左から右へ順番にコピーしていく」
というシンプルなルールです。
重要なポイントを整理すると、
- コピー先(第1引数)は必ず書き換えられる
- 同じキーがあれば、後ろのほうが優先されて上書きされる
- 空オブジェクト
{}をコピー先にすると「元を壊さない新オブジェクト」が作れる - 浅いコピーなので、ネストしたオブジェクトや配列は共有される
- スプレッド
{ ...obj }と役割が似ていて、古いコードほどObject.assignが多く出てくる
という形になります。
スプレッド構文と並べて考えることで、「何をしている関数なのか」が直感的に掴めるようになるので、
ぜひ両方のパターンで書いてみて、動きの違いを手で確認してみてください。
