1. string, number, booleanの代入
配列やオブジェクト以外を代入する場合、値が代入される。
let ori_num = 10;
let new_num = ori_num; // 変数の場合数字を代入
ori_num = 20;
console.log(ori_num, new_num); //output => 20, 10
2. 配列arrayの代入
配列を代入する場合、代入される配列は元の配列を参照する。
そのため、元の配列(ori_arr)の値が変更されると、代入される配列(new_arr)の値も変更されてしまう。
const ori_arr = ['aaa', 'bbb'];
const new_arr = ori_arr; // 元の配列を参照
ori_arr[1] = 'ccc'; // 元の配列の値が変わると…
// 新しく作成した配列も変わる!
console.log(ori_arr,new_arr); // output => ["aaa","ccc"], ["aaa","ccc"]
この対策として以下の4つの方法がある。
対策1:sliceでコピー
const ori_arr =['aaa', 'bbb'];
const new_arr = ori_arr.slice();
ori_arr[1] = 'ccc'; //元の配列の値を変えても...
// 新しく作成した配列には反映されない!
console.log(ori_arr, new_arr); // output => ["aaa","ccc"] ["aaa","bbb"]
対策2: 新しい配列作成+concat
const ori_arr =['aaa', 'bbb'];
const new_arr = [].concat(ori_arr);
ori_arr[1] = 'ccc'; //元の配列の値を変えても...
// 新しく作成した配列には反映されない!
console.log(ori_arr, new_arr); //["aaa","ccc"] ["aaa","bbb"]
対策3: ES6 spread
const ori_arr =['aaa', 'bbb'];
const new_arr = [...a];
ori_arr[1] = 'ccc'; //元の配列の値を変えても...
// 新しく作成した配列には反映されない!
console.log(ori_arr, new_arr); //["aaa","ccc"] ["aaa","bbb"]
対策4: Array#from
const ori_arr =['aaa', 'bbb'];
const new_arr = Array.from(ori_arr);
ori_arr[1] = 'ccc'; //元の配列の値を変えても...
// 新しく作成した配列には反映されない!
console.log(ori_arr, new_arr); // output => ["aaa","ccc"] ["aaa","bbb"]
3. Objectの代入
オブジェクトを代入する場合、代入されるオブジェクトは元のオブジェクトを参照する。
そのため、元のオブジェクト(ori_obj)の値が変更されると、代入されるオブジェクト(new_obj)の値も変更されてしまう。
const ori_obj = {
a:"aaa"
}
const new_obj = ori_obj; //元のオブジェクトに代入
ori_obj.a = "bbb"; //元のオブジェクトの値を変えると...
// 新しく作成したオブジェクトも変更される!
console.log(ori_obj, new_obj); // output => {a:"bbb"}, {a:"bbb"}
そのための対策方法は下記の通り。
対策?:assignを使用(浅いコピー)
Object#assignは浅いコピー(shallow copy)のため、
オブジェクトの中のオブジェクトの値(下記の例だとshallow.b.c)は元のオブジェクトobjに依存してしまう。
const obj = {
a : 'aaa',
b: {
c: 'ccc'
}
}
//浅いコピー (shallow copy)
const shallow = Object.assign({}, obj);
obj.a = 'change'; // オブジェクトを変更
obj.b.c ='change'; // オブジェクトの中のオブジェクトを変更
console.log(obj, shallow);
// output
// obj = {a:"change",b:{c:"change"}}
// shallow = {a:"aaa", b:{c:"change"}} オブジェクトの中のオブジェクトは変更される
そこで、以下のような実装でこの問題を解決する。
対策:JSON.parse(JSON.stringify(obj))を使用(深いコピー)
JSON#parseはstringをJSONに変換し、
JSON#stringifyはJSONをstringに変換する。
const obj = {
a : 'aaa',
b: {
c: 'ccc'
}
}
//深いコピー (deep copy)
const deep = JSON.parse(JSON.stringify(obj));
obj.a ='change';
obj.b.c ='change';
console.log(obj, deep);
// output
// obj = {a:"change",b:{c:"change"}}
// shallow = {a:"aaa", b:{c:"ccc" }}
JSON.parse(JSON.stringify(obj))が深いコピーになる理由
// JSON.stringify(obj)が
JSON.parse("{aaa:bbb,{ccc:ddd}}");
// のようにいったん文字列に置き換えているから