Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
14
Help us understand the problem. What is going on with this article?
@JetNel0

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

More than 1 year has passed since last update.

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}}");
// のようにいったん文字列に置き換えているから
14
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
JetNel0
4月からⅢ年目の社会人です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
14
Help us understand the problem. What is going on with this article?