”データ(オブジェクト)”としているのは、
- オブジェクトにすると話が広がる( function や getter / setter 等も含むよね)
- そういったオブジェクトをディープコピーする機会に会ったことがない
からです。で、どうするかですが、
- structuredClone を使う (2022/04/12追記)
使える環境でサポート対象の型のデータなら、これが良さそうです。
以下の話は、使えなかったときの参考になれば、ぐらいしょうか。。 - ライブラリが使える環境であればそれを頼る
- JSON.parse、JSON.stringify でコピーしても問題ないデータであるなら使う
かなと思います。そして避けるのは、
- Objects.assign を使う
でしょうか。説明を読むと勘違いしそうですが、シャローコピーなので駄目でしょう。
ということで、それぞれどんな感じか見ていきたいと思います。
ライブラリは以下を試してみます。
コピー元のデータ
以下のデータを例に試します。
const data = {
n: 1,
s: 'abc',
d: new Date('2022-01-01T00:00:00Z'),
u: undefined,
o: {
n: 2,
s: 'def',
d: new Date('2022-01-02T00:00:00Z'),
u: undefined,
}
};
jQuery ライブラリを使う
import $ from 'jquery';
const j = $.extend(true, {}, data);
console.log(j);
コンソールに出力される結果は、
ということで、undefined だった data.u、data.o.u が消失していますね。
使用するなら許容できるか検討が必要ですが、私自身が使う範囲では問題にならないと思いました。
lodash ライブラリを使う
import _ from 'lodash';
const l = _.cloneDeep(data);
console.log(l);
コンソールに出力される結果は、
同じですね。
angular ライブラリを使う
import angular from 'angular';
const a = angular.copy(data);
console.log(a);
コンソールに出力された結果は、lodash と同じだったので割愛します。
JSON.parse、JSON.stringify を使う
const s = JSON.parse(JSON.stringify(data));
console.log(s);
コンソールに出力される結果は、
- 日付が文字列になった(s.d、s.o.d)
- undefined が消失した(s.u、s.o.u)
ということで、こちらも使う場合は許容できるか検討が必要でしょう。
数値や文字列でない型が含まれるデータで使うとハマるかもしれません。
Objects.assign を使う
シャローコピーなことを後で確認する為に、Objects.assign も使ってみます。
const o = Object.assign({}, data);
console.log(o);
コンソールに出力される結果は、
と一見良さそうですが、コピー先は以下と同様でディープコピーになっていません。
const o = { ...data };
ディープコピーされているか
コピー元のデータを更新した後、コピー先のデータをそれぞれ出力してみます。
結果はコメントに記載しました。
data.o.n = 9;
console.log(j); // j.o.n = 2 : jquery
console.log(l); // l.o.n = 2 : lodash
console.log(a); // a.o.n = 2 : angular
console.log(s); // s.o.n = 2 : JSON.stringify, JSON.parse
console.log(o); // o.o.n = 9 : Objects.assign
ということで、Objects.assign 以外は大丈夫ですね。
Objects.assign の場合、コピー先を変えたつもりがコピー元も変わるので、勘違いして使っているとハマるかもしれません。
o.o.n = 7;
console.log(data); // data.o.n = 7
ということで、どれを選択するにしても、コピー対象のデータで問題ないか検討してからの方が良いでしょう。
コメント