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}}");
// のようにいったん文字列に置き換えているから