LoginSignup
20

More than 3 years have passed since last update.

javascriptの代入の基礎(深いコピー、浅いコピー)

Last updated at Posted at 2020-04-03

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#parsestringJSONに変換し、
JSON#stringifyJSONstringに変換する。

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20