JavaScriptでのオブジェクトのディープクローニングのしくみ
序章
JavaScriptを使用したコーディングを計画している場合は、オブジェクトがどのように機能するかを理解する必要があります。 オブジェクトはJavaScriptの最も重要な要素の1つであり、オブジェクトを深く理解することは常に役立ちます。
JavaScriptでオブジェクトを正しく複製する方法を理解することが重要です。 オブジェクトの浅いコピーと深いコピーを作成することができます。 オブジェクトの浅いコピーは、元のオブジェクトを参照します。 したがって、元のオブジェクトに加えられた変更はすべてコピーに反映されます。 ディープコピーは、元のオブジェクトのすべての要素のコピーです。 元のオブジェクトに加えられた変更は、コピーに反映されません。 この記事では、Lodashライブラリを使用してオブジェクトのディープコピーを作成します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- マシンにインストールされているNodeの最新バージョン。 Nodeをインストールするには、このNode.jsチュートリアルのインストール方法に概説されている手順に従ってください。
- npmを使用してモジュールとパッケージをインストールする方法、および
package.json
ファイルを構成する方法の理解。 この記事npmおよびpackage.jsonでNode.jsモジュールを使用する方法はこれに役立ちます。 - JavaScriptでコーディングする方法と呼ばれるこのシリーズで見つけることができるJavaScriptでのコーディングの基本的な理解
ステップ1-オブジェクトを再割り当てして浅いコピーを作成する
オブジェクトを取り込んで変更する関数を作成する場合は、元のオブジェクトを変更するのではなく、オブジェクトのコピーを作成してそのコピーを変更することをお勧めします。
新しいオブジェクトを初期化し、それを変数testObject
に割り当てます。 このオブジェクトには、キーとしてa
、b
、およびc
の文字があり、1
、2
、および3
が必要です。それぞれ値として。
JavaScriptでオブジェクトを作成します。
let testObject = {
a: 1,
b: 2,
c: 3
};
次に、testObject
をtestObjectCopy
という新しい変数に割り当てて、操作するこのオブジェクトのコピーを作成してみます。
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
testObject
のキーa
の値を変更します。 9
と等しくなるように設定します。
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
testObject.a = 9;
この変更は、testObject
オブジェクトにのみ反映されると予想される場合があります。 console.log
ステートメントを使用して、a
の値がtestObjectCopy
にあるかを確認します。
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
testObject.a = 9;
console.log(testObjectCopy.a);
このconsole.log
ステートメントは、testObject
ではなくtestObjectCopy
を参照しているにもかかわらず、9
をコンソールに出力します。 これは、新しい変数testObjectCopy
を作成しても、testObject
コピーが作成されないためです。 代わりに、testObject
を参照しています。 元のオブジェクトに加えた変更は、想定されるコピーに反映され、その逆も同様です。
オブジェクトを新しい変数に再割り当てすると、元のオブジェクトの浅いコピーのみが作成されます。 次のステップでは、オブジェクトをループすることが、ディープコピーを作成するための可能な解決策になる可能性があることを探ります。
ステップ2–オブジェクトをループして浅いコピーを作成する
オブジェクトをループして各プロパティを新しいオブジェクトにコピーすることは、実行可能な解決策のように思えるかもしれません。 これをテストするには、object
という引数を取るcopyObject
という関数を作成します。
const copyObject = object => {
};
copyObject
内で、空のオブジェクトを保持するcopiedObj
という変数を宣言します。
const copyObject = object => {
let copiedObj = {};
};
object
のキーごとにfor
ループを作成します。 copiedObj
のキーと値のペアをobject
のキーと値のペアと同じに設定します。
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
};
このcopyObject
関数の最後のステップとして、copiedObj
を返します。
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
return copiedObj;
};
copyObject
を配置したら、testObject
というオブジェクトを作成し、copyObject
のパラメーターとして渡します。
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
return copiedObj;
};
const testObject = {
a: 5,
b: 6,
c: {
d: 4
}
};
copyObject(testObject);
copyObject
関数の結果を確認するには、console.log
を使用して、コンソールに出力されたcopyObject(testObject)
の出力を確認します。
console.log(copyObject(testObject));
これにより、次の出力が生成されます。
Output{ a: 5, b: 6, c: { d: 4 } }
testObject
をループしてコピーを作成すると、目的の結果が得られるように見える場合があります。 しかし、このアプローチで探している結果が得られない理由はいくつかあります。
- 各プロパティを新しいオブジェクトにコピーするループは、オブジェクトの列挙可能なプロパティのみをコピーします。 列挙可能なプロパティは、
for
ループおよびObject.keys
に表示されるプロパティです。 - コピーされたオブジェクトには新しい
Object.prototype
メソッドがありますが、これはオブジェクトをコピーするときに必要なものではありません。 これは、元のオブジェクトに加えた変更が、コピーされたオブジェクトに反映されることを意味します。 - オブジェクトにオブジェクトであるプロパティがある場合、コピーされたオブジェクトは、実際のコピーを作成するのではなく、実際には元のオブジェクトを参照します。 これは、コピーされたオブジェクト内のネストされたオブジェクトを変更すると、元のオブジェクトも変更されることを意味します。
- プロパティ記述子はコピーされません。
configurable
やwritable
などをfalse
に設定すると、コピーされたオブジェクトのプロパティ記述子はデフォルトでtrue
になります。
オブジェクトをループすることで浅いコピーを作成できますが、この方法を使用して深いコピーを作成することはできません。 ありがたいことに、ディープコピーを作成するためのソリューションを提供するライブラリが利用可能です。
ステップ3–Lodashを使用して浅いコピーと深いコピーを作成する
数値や文字列などのプリミティブ型のみを格納する単純なオブジェクトの場合、上記のような浅いコピー方法が機能します。 ただし、オブジェクトが他のネストされたオブジェクトへの参照を特徴としている場合、実際のオブジェクトはコピーされません。 参照をコピーするだけです。
ディープコピーの場合、1つの優れたオプションは、Lodashのような信頼できる外部ライブラリを使用することです。 Lodashは、浅いコピーと深いコピーを実行できる2つの異なる機能を提供するライブラリです。 clone
とclonedeep
です。
Lodash clone
およびclonedeep
機能をテストするには、最初にLodashをインストールする必要があります。
- npm install --save lodash
lodashがインストールされたら、require()
関数を使用して、Lodashが提供するすべての関数にアクセスします。
const _ = require('lodash');
これで、コードでclone
およびclonedeep
関数を使用できます。 externalObject
というオブジェクトを作成します。 'Gator'
の値を持つキーanimal
を指定します。
const externalObject = {
animal: 'Gator'
};
originalObject
という別のオブジェクトを作成します。 originalObject
は、それぞれに異なる値を持つ7つのプロパティを格納します。 プロパティd
は、animal
のプロパティと'Gator'
の値を持つexternalObject
を参照します。
const originalObject = {
a: 1,
b: 'string',
c: false,
d: externalObject
};
clone
で浅いコピーを作成する
定数変数shallowClonedObject
を宣言し、Lodash clone
関数を使用して、originalObject
のシャローコピーに割り当てます。
const shallowClonedObject = _.clone(originalObject);
externalObject
のanimal
キーの値を再割り当てします。 'Crocodile'
と同じに設定します。 2つのconsole.log
ステートメントを使用して、originalObject
とshallowClonedObject
の両方を画面に出力します。
externalObject.animal = 'Crocodile';
console.log(originalObject);
console.log(shallowClonedObject);
このコードの出力は次のようになります。
Output{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
externalObject
のanimal
プロパティを新しい値に割り当てると、originalObject
とshallowClonedObject
の両方が変更されます。 console.log
ステートメントはこれを示します。 これは、浅いクローンが新しいオブジェクトを作成するのではなく、externalObject
への参照のみをコピーできたために発生します。
clonedeep
でディープコピーを作成する
Lodash clonedeep
関数を使用して、ディープコピーを作成できます。
const deepClonedObject = _.clonedeep(originalObject);
deepClonedObject
を配置した状態で、externalObject
のanimal
キーの値を'Lizard'
と等しくなるように再割り当てします。
ここでも、2つのconsole.log
ステートメントを使用して、originalObject
とdeepClonedObject
の両方を画面に出力します。
externalObject.animal = 'Lizard';
console.log(originalObject);
console.log(deepClonedObject);
このコードの出力は次のようになります。
Output{ a: 1, b: 'string', c: false, d: { animal: 'Lizard' } }
{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
originalObject
の'animal'
プロパティは変更されますが、deepClonedObject
の場合、参照をコピーするのではなく、オブジェクト全体が個別にコピーされるため、'Crocodile'
のままになります。 clonedeep
関数を使用すると、オブジェクトのディープコピーを正常に作成できます。
結論
JavaScriptでオブジェクトを複製する方法を理解することが重要です。 オブジェクトを再割り当てしてループすることにより、オブジェクトの浅いコピーを作成しました。 また、Lodashライブラリを使用して、オブジェクトの浅いコピーと深いコピーの両方を作成しました。
JavaScriptのオブジェクトについて詳しく知りたい場合は、このJavaScriptのオブジェクトについてチュートリアルから始めるのが最適です。 これをさらに一歩進めて、オブジェクトメソッドをコピーする方法を学びたい場合は、 JavaScriptでのオブジェクトのコピーの記事で、正しい方向を示すことができます。