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?

jsでのdeep copyの方法

Posted at

はじめに

jsでの開発をしていると、deep copyが必要になる時が多いですよね。
色々方法がある中で、どんな場面でどんな方法を使うべきかまとめてみました。

Deep Copyとは?

元オブジェクトに影響を与えずに同じ値を持つ新しいオブジェクトを生成することです。

コピー先のオブジェクトのプロパティがコピー元のオブジェクトのプロパティと同一の参照(同じ値を指す)で共有しないコピー方法のこと

対比する概念としてshallow copyがあって、shallow copyは新しいオブジェクトに変更があると元オブジェクトにも影響が出るものとなっています。

Deep Copyの方法

1. Json.parse(Json.stringify())

jsでオブジェクトはJSONの形にすることができるので、Jsonクラスのparseメソッドを利用して同じオブジェクトを生成することができます。

個人的にはdeep copyを行うにあたってどんな処理が行われているか一番わかりやすいと感じます。

2. structuredClone

ブラウザAPIとしてネイティブな実装になっているメソッドです。

3. cloneDeep

lodashというライブラリが提供するメソッドです。

実例

const original = {
  name: "田中",
  info: {
    age: 25,
    hobbies: ["読書", "旅行"]
  },
  date: new Date()
};

// 1. JSON.parse(JSON.stringify)
const copy2 = JSON.parse(JSON.stringify(original));

// 2. structuredClone
const copy1 = structuredClone(original);

// 3. lodash の cloneDeep
import _ from 'lodash';

const copy3 = _.cloneDeep(original);

比較

1. Json

最もシンプルで広くサポートされている方法です。
しかし、stringifyでの実装になっているため、オブジェクトによって正しく処理されない可能性があります。

  • undefined(削除される)
  • 関数(削除される)
  • Symbol(削除される)
  • 循環参照(エラー発生)
  • Date(文字列に変換)
  • Map/Set(空のオブジェクトに変換)

2. structuredClone

Date, Map, Set, ArrayBuffer, Blob, Fileなどのオブジェクトを正しくコピーすることができます。

循環参照(circular references)に対応していますが、関数やSymbolなどはコピーできない制限があります。

また、これは業務で経験したことですが、structuredCloneは2022年にできた機能であるためそれ以前のバージョンのブラウザでは正しく動作しません。
ほとんど起きないことではありますが、もしdeep copyで権限などの処理をしている場合は、想定外の挙動をする可能性がありますね。

3. lodash

一番柔軟で機能が豊富な方法です。

customizerという関数があってカスタマイズ可能です。他の方法に比べて違うところは、ほぼすべてのJavaScriptオブジェクトに対応しています。

循環参照にも対応していますが、外部ライブラリへの依存が必要で、パフォーマンスは3つの中で最も低いです。

循環参照とは?

私は調べているときに循環参照がよくわからなかったので一緒にまとめてみました。

循環参照とは、オブジェクトの中に直接または間接的に自分自身への参照が含まれている状態のことです。

以下のような場面がその例となります。

// 循環参照を含むオブジェクト
const family = {
  name: "田中家"
};

const father = {
  name: "田中太郎",
  family: family  // family への参照
};

family.father = father;  // father への参照

// JSON.stringify で変換しようとすると...
try {
  console.log(JSON.stringify(family));
} catch (error) {
  console.log("エラー発生:", error.message);
  // 出力: エラー発生: Converting circular structure to JSON
}
0
0
0

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?