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でのオブジェクトのコピーの記事で、正しい方向を示すことができます。