JavaScript での配列のディープ コピー

Subodh Poudel 2023年10月12日
  1. JavaScript のシャロー コピーとディープ コピーの概要
  2. structuredClone() メソッドを使用して JavaScript でオブジェクトのディープ コピーを作成する
  3. JSON.parse() および JSON.stringify() メソッドを使用して JavaScript でオブジェクトのディープ コピーを作成する
  4. Lodash ライブラリを使用して、JavaScript でオブジェクトのディープ コピーを作成する
JavaScript での配列のディープ コピー

この記事では、ディープ コピーとシャロー コピーの概念について説明します。 この記事では、JavaScript で配列に対してディープ コピーを実行する方法も紹介します。

JavaScript のシャロー コピーとディープ コピーの概要

JavaScript では、オブジェクトは 2つの方法でコピーできます。 ディープコピーとシャローコピーです。

まず、浅いコピーについて説明しましょう。 オブジェクトのシャロー コピーには、ソース オブジェクトのプロパティと同じ参照を指すプロパティがあります。

ここで、ソース オブジェクトはコピー元のオブジェクトです。 オブジェクトとその浅いコピーは同じ参照を共有するため、一方に加えられた変更は他方のオブジェクトに反映されます。

例でそれを理解しましょう。

name という名前のプロパティと kevin という値を持つオブジェクト student1 を考えてみましょう。 次に、別の変数 student2 を作成し、student2 の値を割り当てます。

let student1 = {name: 'kevin'}

let student2 = student1

ここでは、student1 オブジェクトの浅いコピーを作成しました。 それでは、name プロパティの値を student2 オブジェクトから別のものに変更してみましょう。

たとえば、新しい値は john です。 student1student2 の両方のオブジェクトを印刷すると、値は同じです: john.

コード例:

let student1 = {name: 'kevin'}

let student2 = student1

 student2.name = "john"

console.log(student1)
console.log(student2)

出力:

{
  name: "john"
}
{
  name: "john"
}

これは、オブジェクトの浅いコピーがどのように動作するかです。 両方のオブジェクトが同じ参照を共有しているため、ソース オブジェクトのプロパティを変更できます。

ただし、オブジェクトのディープ コピーはまったく逆の動作をします。 コピー オブジェクトとソース オブジェクトは同じ参照を指していないため、オブジェクトのプロパティの 1つを変更しても、他のプロパティは変更されません。

以下のセクションでは、ディープ コピーと JavaScript でそれを実現する方法について学習します。

structuredClone() メソッドを使用して JavaScript でオブジェクトのディープ コピーを作成する

JavaScript でオブジェクトのディープ コピーを作成する方法の 1つは、structuredClone() メソッドを使用することです。 このメソッドは、オブジェクトのディープ クローンを作成する構造化クローン アルゴリズムを使用します。

このメソッドは、複製されるオブジェクトをパラメーターとして受け取ります。 クローニングを実行しましょう。

たとえば、name プロパティの値 kevin を含む上記の student1 オブジェクトを考えてみましょう。 次に、structuredClone() メソッドを使用して、student1 オブジェクトをそのパラメーターとして指定します。

最後に、メソッドを変数 student2 に割り当てます。 これにより、student2 オブジェクトが student1 オブジェクトのディープ コピーになります。

次に、student2 オブジェクトのプロパティを john に変更します。

今度は両方のオブジェクトを印刷すると、プロパティの値が同じではありません。 student1 オブジェクトの値は kevin になり、student2name プロパティは john になります。

コード例:

let student1 = {
  name: 'kevin',

}

let student2 = structuredClone(student1)

student2.name = 'john'

console.log(student1)
console.log(student2)

出力:

{
  name: "kevin"
}
{
  name: "john"
}

これが structuredClone() メソッドを使用して JavaScript でディープ コピーを実行する方法です。

JSON.parse() および JSON.stringify() メソッドを使用して JavaScript でオブジェクトのディープ コピーを作成する

JSON.parse() および JSON.stringify() メソッドを使用して、オブジェクトのディープ コピーを作成することもできます。 JSON.stringify() メソッドはオブジェクトまたは値を文字列に変換し、JSON.parse() メソッドは JSON 文字列を解析してオブジェクトまたは値を作成します。

まず、JSON.stringify() メソッドを使用してオブジェクトを文字列に変換し、次に JSON.parse() メソッドを使用してオブジェクトを解析してオブジェクトのディープ コピーを作成します。

たとえば、同じ student1 オブジェクトを考えて、JSON.stringify() メソッドを使用してオブジェクトを文字列に変換します。 次に、結果に対して JSON.parse() メソッドを使用します。

式を変数 student2 に割り当てます。 次に、上で行ったように最初のオブジェクトのプロパティを変更し、両方のオブジェクトを出力します。

コード例:

let student1 = {
  name: 'kevin',

}


let student2 = JSON.parse(JSON.stringify(student1))

student2.name = 'john'

console.log(student1)
console.log(student2)

出力:

{
  name: "kevin"
}
{
  name: "john"
}

これら 2つのオブジェクトのプロパティの値が異なることがわかります。これは、ソース オブジェクトのディープ コピーを作成したことを意味します。 したがって、JSON.parse() および JSON.stringify() メソッドを使用して、JavaScript でオブジェクトのディープ コピーを実行できます。

しかし、関数やオブジェクトを操作するときに問題が発生します。 問題をより明確に把握するために、関数と Date() オブジェクトを含むオブジェクトのディープ クローンを実装してみましょう。

以下の例のように、新しいフィールドを student1 オブジェクトに追加します。

コード例:

let student1 = {
  name: 'kevin',
  age: function() {
    return 24;
  },
  enrolledDate: new Date()

}

次に、JSON.parse()JSON.stringify() 関数を使用して、上記のようにオブジェクトのディープ コピーを作成します。 次に、最初のオブジェクトの name プロパティを変更します。 最後に、両方のオブジェクトを印刷します。

コード例:

let student2 = JSON.parse(JSON.stringify(student1))
student2.name = 'john'

console.log(student1)
console.log(student2)

出力:

{
  name: 'kevin',
  age: [Function: age],
  enrolledDate: 2023-01-19T16:15:30.914Z
}
{ name: 'john', enrolledDate: '2023-01-19T16:15:30.914Z' }

ここでは、オブジェクトのディープ コピーに顕著な問題が見られます。 最初の問題は、関数に複製されたオブジェクトがないことです。

もう 1つの問題は、ネストされたオブジェクト new Date() の型の変更です。 複製後、new Date() オブジェクトは String 型に変更されます。 日付の周りの引用符に気付くことができます。

このように、JSON.parse() および JSON.stringify() メソッドを使用する場合、関数と型を含むオブジェクトのディープ コピー中に問題が発見されました。 この記事の次のセクションで問題を解決します。

Lodash ライブラリを使用して、JavaScript でオブジェクトのディープ コピーを作成する

lodash ライブラリを使用して、関数とネストされたオブジェクトを複製する際に、この問題を解決できます。 lodash はメソッド cloneDeep() を提供します。このメソッドは、ソース オブジェクトをパラメーターとして取り、それをディープ クローンします。

以下のコマンドでライブラリをインストールできます。

npm i -g lodash

たとえば、コードの先頭でライブラリを必要とします。 定数 _ に割り当てます。

この定数を使用して、student1 オブジェクトがパラメーターである cloneDeep() を呼び出します。 オブジェクトのプロパティの値を以前と同じように変更します。 最後に、両方のオブジェクトを印刷します。

コード例:

const _ = require('lodash')
let student1 = {
  name: 'kevin',
  age: function() {
    return 24;
  },
  enrolledDate: new Date()

}


let student2 = _.cloneDeep(student1)

student2.name = 'john'

console.log(student1)
console.log(student2)

出力:

{
  name: 'kevin',
  age: [Function: age],
  enrolledDate: 2023-01-23T15:02:56.059Z
}
{
  name: 'john',
  age: [Function: age],
  enrolledDate: 2023-01-23T15:02:56.059Z
}

最後に、オブジェクトをディープ クローンしても、関数とネストされたオブジェクトを保持できます。 したがって、lodash ライブラリを使用して、JavaScript でオブジェクトのディープ クローンを作成できます。

著者: Subodh Poudel
Subodh Poudel avatar Subodh Poudel avatar

Subodh is a proactive software engineer, specialized in fintech industry and a writer who loves to express his software development learnings and set of skills through blogs and articles.

LinkedIn

関連記事 - JavaScript Array