thumbnail

JSでのディープコピー、シャローコピー

2022/02/05

そろそろディープコピーmethodがモダンブラウザで実装されるかも?

JSのディープコピーが可能なstructuredClonemethodは以前からFirefoxのみで使用可能でしたが、近々その他のモダンブラウザでも実装されるかもしれません。 (SafariのPreview版ではすでに実装済)

このstructuredCloneを使用しれば、今まではlodashJSON.parseを使って行っていたディープコピーがよりシンプルに行えるようになります。

const obj = {
	a: 'original',
	b: {
		c: 'original'
	},
}

// deep copy
const copy = structuredClone(obj)

copy.a = 'change'
copy.b.c = 'change'

console.log(obj.b.c)  // -> 'original'

console.log(copy.b.c) // -> 'change'

そもそもディープコピー、シャローコピーとは?

ここから先はディープコピー、シャローコピーがよくわかってない人向けの説明です。

obj.aobj.b.cはそれぞれどうなる?

ディープコピー、シャローコピーを理解するために以下のobj.aobj.b.cがそれぞれどのように変化するか考えてみます。

const obj = {
	a: 'original',
	b: {
		c: 'original'
	},
}

const copy = Object.assign({}, obj)
// もしくはconst copy = { ...obj }とか

copy.a = 'change'
copy.b.c = 'change'

console.log(obj.a)  // -> ?
console.log(obj.b.c)  // -> ?

答えは以下のとおりです。

console.log(obj.a)  // -> 'original'
console.log(obj.b.c)  // -> 'change'

値を変更したのはobj.b.cにも関わらず、コピー元のデータも一緒に書き換わってしまいました。 これはシャローコピーでcopyオブジェクトを生成したことが原因です。

シャローコピー

JSでの

const copy1 = Object.assign({}, obj)
const copy2 = { ...obj }

のようなオブジェクトのコピー方法はシャローコピーになります。

シャローコピーではコピー元のプロパティがprimitive型(stringやboolean)であれば、そのまま値がコピーされますが、object型であれば、その参照アドレスがコピーされることになります。

したがって、先の例でのobj.bcopy.bは同じアドレスにあるプロパティを参照していることになるので、「copy.bを変更するとobj.bも変更される」という現象が起きるわけです(逆も然り)。

ディープコピー

コピー元とコピー先で同じ参照先のプロパティを共有してもらっては困ることも多いので、その場合はディープコピーを使用します。

ディープコピーにはいくつか方法がありますが、メジャーなところだと以下の2つになると思います。

const copy1 = JSON.parse(JSON.stringify(obj)) // 一度,文字列に変換して再度オブジェクトとして構築
const copy2 = _.cloneDeep(obj) // lodashのmethod

これらの方法はコピー元のプロパティがobject型だったとしてもコピー先で別のobjectとしてプロパティが生成されるので、シャローコピーで起こっていたようなプロパティの共有は発生しません。

シャローコピーやディープコピーの特性を知らずに実装しているとバグの温床になりかねないので、注意しましょう。

おわり

ちなみに自分だったら、objのコピーは↓みたいに書きます。 参考までに

const obj = {
	a: 'original',
	b: {
		c: 'original'
	},
}

// 「cが変わる」=「bを新しくする」と考え、
const newB = { c: 'change' }
const newObj = {
	...obj,
	b: newB  // オブジェクトごと変更してあげるのもあり
}
author picture

Mitsuru Takahashi

京都市内にてフリーランスエンジニアとして活動しています。

detail

Profile

author picture

Mitsuru Takahashi

京都市内にてフリーランスエンジニアとして活動しています。

detail

© 2022 mitsuru takahashi