テクメモ

備忘録

Object.assignの挙動で勘違いしていたこと

知ってる人からしたら、なにをいまさらという感じかもしれませんが Object.assignの挙動に関して勘違いしていたことがあり、業務中にハマったので備忘録程度に書きます。

勘違い1:Object.assignの返り値

Object.assignの返り値について勘違いしていました。 引数で渡したオブジェクトを合成した新しいオブジェクトを返す

のではなく

第2引数以降に渡したオブジェクトを、第1引数に渡したオブジェクトに合成して返す

ものでした。 MDNにも

Object.assign() メソッドは、すべての列挙可能なプロパティの値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。戻り値としてコピー先オブジェクトを返します。

Object.assign() - JavaScript | MDN

と書いてありました。

よって、以下のように

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 4, c: 5 };

const obj3 = Object.assign(obj1, obj2);

console.log(obj1); // { a: 1, b: 4, c: 5 }

console.log(obj3); // { a: 1, b: 4, c: 5 }

obj1もobj3も中身が書き換わった状態になっています。

勘違い2:引数で渡したオブジェクトがネストされているときの挙動

Object.assignはシャローコピーのため、第2引数以降に渡したオブジェクトがネストされていた場合、オブジェクト参照がコピーされるようです。

const obj1 = {a:1, b:2};
const obj2 = {b:3, c:4, d:{a:5, b:6}};   

Object.assign(obj1, obj2);

console.log(obj1);  // {a:1, b:3, c:4, d:{a:5, b:6}}

obj1.d.a = 999;  // obj1.d.aの値を更新する

console.log(obj1);  // {a:1, b:3, c:4, d:{a:999, b:6}}
console.log(obj2);  // {b:3, c:4, d:{a:999, b:6}} →オブジェクト参照がコピーされているため、obj2.d.aの値が変わっている

コピー先の変更についてコピー元に影響を及ぼしたくないときは ディープコピーしたオブジェクトをコピー元として渡すなりすればよさそうです。

おわりに

初歩的な内容にはなりましたが、このような勘違いしていたこと、業務中ハマった内容は 小さなことでも書いていきたいと思います。

参考

developer.mozilla.org