0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[JS]Objectの値をコピーしたいのに参照先がコピーされちゃう!!??

Last updated at Posted at 2019-09-26

記事下部にコメント指摘の追記あります。

やりたいこと

人類において200000000回は繰り返されているであろう事象。
それはObjectをコピーして、コピーした方の中身を入れ替えたはずが、
コピー元まで入れ替わってしまっているということ。

これはObjectも(もちろんArrayも)参照先をコピーしてしまうことに起因する。
四次元ポケットと似た仕組みだ。(入り口は異なれど中身は一緒)


// あるObjectがあって、
const ObjectA = {
    a:'dog',
    b:'cat',
    c:'bird',
};

// それをコピーする必要があった
const ObjectB = ObjectA;

// コピーした方の中身をちょっとだけ変えたい
ObjectB.a = 'dragon';

// あれ!?!?コピー元まで変わってる!?!?
console.log(ObjectA.a);

//欲しい結果= dog
//実際の結果= dragon

解決策

そこで、Object.assign()を応用します。

const ObjectB = Object.assign({}, ObjectA);

const ObjectA = {
    a:'dog',
    b:'cat',
    c:'bird',
};

//メソッド第一引数のassignが必須。これで新規のObjectに入れ直している。
const ObjectB = Object.assign({}, ObjectA);

// コピーした方の中身を変える
ObjectB.a = 'dragon';

// コピー元は変わってない!コピーした先だけが変わってる!ヨシっ!
console.log(ObjectA.a);
console.log(ObjectB.a);

//実際の結果
// ObjectA.a = 'dog'
// ObjectB.a = 'dragon'

ただこれもシャローコピー(1階層目のみのコピー)なので、
ネストになっていた場合は以下のように参照先がコピーされてしまいます。

// Objectの中にObjectを作る
const ObjectA = { animal: { a: 'dog', b: 'cat' }, creature: { a: 'dragon', d: 'harpy' } };

// さっきと同じく、Object.assign()でコピーする
const ObjectB = Object.assign({},  ObjectA);

// よっしゃ、animalのaを'bird'に入れ替えたろ!
ObjectB.animal.a = 'bird';

console.log(ObjectA.animal.a);
console.log(ObjectB.animal.a);

// 実際の結果= 両方とも'bird'

ディープコピーはやり方を調べると色々でてきますが、
自前でメソッドを定義するのはわりと大変です。

配列であればmap関数などで中身を入れ替えちゃえば良いのですが、
オブジェクトの場合はそうもいきません。

ただディープコピーは多くの人たちが必要としていることもあり、
いろんな言語に対応するライブラリが作られています。

そういうのを使ってみるのも、良いかもしれませんね!(投げやり)

参考:
Jqueryであればextendとか。
https://api.jquery.com/jquery.extend/

もっとわかりやすくかける方法(コメント指摘)

スプレッド構文で書くのが今風ということで、しかもこっちの方が見やすくてわかりやすいですね(IE対応、assignもできないし)

// {}の空オブジェクトに、ObjectAの中身をスプレッド構文で展開してあげる
const ObjectB = { ...ObjectA };

// コピーした方の中身を変える
ObjectB.a = 'dragon';

// コピー元は変わってない!コピーした先だけが変わってる!ヨシっ!
console.log(ObjectA.a);
console.log(ObjectB.a);

//実際の結果
// ObjectA.a = 'dog'
// ObjectB.a = 'dragon'
0
0
3

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?