落とし穴

JavaScript のオブジェクトは参照型ですからオブジェクト、配列は参照渡しになります。よく理解していないと値を更新しても期待通り動作しません。最悪バグを生むことになりかねません。(大抵の場合こういった類のバグは潰すのが大変だったりします)

 
// myCar という名前のオブジェクトを作成
const myCar = {
    make: 'Ford',
    model: 'Mustang',
    year: 1969
};

// newCar は異なるオブジェクトのつもり
// 実際は、同じオブジェクトへの参照になっている
let newCar = myCar;

// newCar のプロパティーを変更する
newCar.make = 'Bayerische Motoren Werke AG';
newCar.model = 'BMW M8 グラン クーペ';
newCar.year = 2021;

// newCar は変更できたが ...
console.log('newCar=', newCar);  // > "newCar=" Object { make: "Bayerische Motoren Werke AG", model: "BMW M8 グラン クーペ", year: 2021 }

// 実は myCar まで書き換わっている
console.log('myCar=', myCar);   // > "myCar=" Object { make: "Bayerische Motoren Werke AG", model: "BMW M8 グラン クーペ", year: 2021 }

// myCar を代入して、初期値に戻したいが。。。
newCar= myCar;

console.log('newCar=', newCar); // > "newCar=" Object { make: "Bayerische Motoren Werke AG", model: "BMW M8 グラン クーペ", year: 2021 }

ぢゃ どうすればいい

オブジェクトや配列を代入するのではなく、ディープ コピーを使う。 コピーには、ディープとシャローがあるということを学習しておきたい。

 

対策

JSONジェイソン.stringifyストリングファイ() で文字列に変換し JSON.parse() でオブジェクトに戻すことでコピーする。ただし、このやり方は Date 型のプロパティ値を正しく復元できなくなるという問題がある。

 

 

let newCar = JSON.parse(JSON.stringify(myCar));

対策

Object.assign() を使う。ただし、オブジェクト内にオブジェクトがある場合は、中のオブジェクトが参照渡しになってしまうので注意する。

let newCar = Object.assign({}, myCar);

対策

Lodash の cloneDeep() を使う。

   

Installation

Using npm:
$ npm i --save lodash.clonedeep
In Node.js:
const cloneDeep = require('lodash.clonedeep');

let newCar = cloneDeep(myCar);

対策

配列は、concat() を使う。

 
const old_array = [ 1, 2, 3 ];

const new_array = old_array.concat();