1
0

JavaScriptでは、オブジェクトと配列は参照渡しで行われます。まず、この概念について簡単に説明します。

参照渡し

引用型は、総称として Object 型と呼ばれます。細分すると、Object 型、Array 型、Date 型、RegExp 型、Function 型などがあります。

引用型の値は参照によってアクセスされます

参照オブジェクトの保存方法は、スタックに変数名を保存し(その変数の値はヒープにあるデータのポインタ、つまりオブジェクトがヒープに保存されているアドレスです)、ヒープにデータそのものを保存します。

オブジェクトは参照渡しを使用します。あるオブジェクトを新しい変数に代入すると、そのオブジェクトがヒープに保存されているアドレスが代入され、ヒープのデータそのものではありません。つまり、2つのオブジェクトは同じ記憶空間を指しており、どちらかのオブジェクトが変更されると、実際には記憶空間の内容が変更されるため、2つのオブジェクトは連動します。

image.png

コード例

//ケース1
var a = [1, 2, 3];
var b = a;
a = [4, 5, 6];
console.log(b); // [1, 2, 3]

上記のコードでは、配列は基本データ型のように見えますが、実際には以下のように動作します:

//ケース2
var a = [1, 2, 3];
var b = a;
a.pop();
console.log(b); // [1, 2]

これはなぜでしょうか?

a = [4, 5, 6]; // これはa参照そのものを変更しており、配列オブジェクトを変更していません。
a.pop(); // これは配列オブジェクトを変更しており、a参照は変更されません。
b = a; // この操作により、bは配列オブジェクトを直接指すようになります。bがaを指し、aが配列を指すわけではありません。
// そのため、a参照を変更してもb参照には影響がなく、配列オブジェクトを変更すると影響があります。

上記コードの図示

image.png

解決策


1. JSON文字列に変換してからオブジェクトまたは配列に戻す

JSON.parse(JSON.stringify(...))
var a = [1, 2, 3];
var b = JSON.parse(JSON.stringify(a));
a.pop();
console.log(b); // [1, 2, 3]

2. Lodashライブラリを使用

Lodashには、元のデータを再帰的にディープコピーする _.cloneDeep(value) 関数があります。詳細はこちらをご覧ください。

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); // => false
const _ = require('lodash');

var a = [1, 2, 3];
var b = _.cloneDeep(a);
a.pop();
console.log(b); // [1, 2, 3]

長文をお読みいただき、ありがとうございました。

1
0
9

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
1
0