[JS]深放射&浅放射
30254 ワード
概要
前述のバージョンJS、オリジナルタイプ&オブジェクトで説明したように、JSは複数のオブジェクトをサポートしており、少し複雑なデータ構造が形成されている場合、配列またはオブジェクトにデータを格納する作業が多い.
「レプリケーション」の概念は、このような観点から、単純な元のタイプについては、通常考えられるレプリケーションかもしれませんが、オブジェクトレベルからレプリケーションについて深く考える必要があります.
本題
その前に確認する
値のコピー
📍 問題の状況を示す
{
/**
* 값 복사
* - 분리된 메모리 공간에, 데이터를 각각 저장(공유 X) 💡
*/
let num1 = 1;
let num2 = num1;
num2 = 2;
console.log(`num1 : ${num1}, num2 : ${num2}`);
// num1 : 1, num2 : 2
// 🔍 원본 데이터 값 보존
/**
* 객체 복사
* - 동일한 메모리 공간 내, 주소값 데이터에 대해, 동일한 주소값 데이터를 각각 저장(공유 O) 💡
*/
let person = {
name: "min",
job: "developer",
salary: 5000,
};
let clonePerson = person;
clonePerson.salary = 6000;
console.log(`Salary - Person : ${person.salary}, ClonePerson : ${clonePerson.salary}`);
// Salary - Person : 6000, ClonePerson : 6000
// 🔍 원본 데이터 값 변경됨
}
📍 複製参照タイプ-浅い複製(Shallow Copy)
参照タイプのコピーは、基本的に浅いコピーと深いコピーに分けられます.ここでは、まず浅いコピーについて説明します.
上記の場合、元のタイプではなく通常のオブジェクトの単純な代入レプリケーションによる問題を解決し、そのオブジェクトのすべての内部データが元のタイプ値で構成されている場合は、Shallow Copyを使用して完全に解決できます.
JSでの浅いコピーの方法はいくつかありますが、ES 6+以降の標準では、通常と比較的簡単な方法は:
/**
* Shallow Copy - Object.assign() 사용
*/
let myCat = {
name: "Cash",
age: 5,
weight: "3kg",
};
let myCat2 = Object.assign({}, myCat);
myCat2.name = "Rolly";
myCat2.age = 2;
console.log(myCat); // { name: 'Cash', age: 5, weight: '3kg' }
console.log(myCat2); // { name: 'Rolly', age: 2, weight: '3kg' }
/**
* Shallow Copy - Spread Operator 사용
*/
let myCaptin = {
name: "Iron Man",
rank: 1,
gender: "M",
};
let myCaptin2 = { ...myCaptin };
myCaptin2.name = "Captin America";
myCaptin2.rank = 2;
console.log(myCaptin); // { name: 'Iron Man', rank: 1, gender: 'M' }
console.log(myCaptin2); // { name: 'Captin America', rank: 2, gender: 'M' }
💡 [注意]アレイ(Array)は、オブジェクト(Spread OperatorまたはArray Object)ではなく、埋め込み方法です.prototyp.slice( ) , Array.prototype.map()などの方法も既存のアレイデータを操作して新しいアレイ自体の概念を返すため,オブジェクト上で概念と同じShallow Copyを実行することができる.
この2つの方法から、データは、最初のレプリケーションオブジェクトと比較して、レプリケーション値などの変数ごとに保持されているようです.
さっき話した時~いいみたい.こう言うのは理由がある.
次の状況を見てください.
/**
* Shallow Copy 에 함정
*/
let myCar = {
name: "부릉이",
price: 7000,
specialMode: {
mode: "Fly",
},
};
let myCar2 = { ...myCar };
myCar2.name = "따릉이";
myCar2.price = 4000;
myCar2.specialMode.mode = "Dive";
console.log(myCar); // { name: '부릉이', price: 7000, specialMode: { mode: 'Dive' } }
console.log(myCar2); // { name: '따릉이', price: 4000, specialMode: { mode: 'Dive' } } 🔍
// 두 car에 대해 프로퍼티 비교
console.log(myCar.name === myCar2.name); // false
console.log(myCar.specialMode === myCar2.specialMode); // true 🔍
console.log(myCar.specialMode.mode === myCar2.specialMode.mode); // true 🔍
いずれもよく、最後に、SpecialMode(オブジェクト)Propertyの内部には、モードPropertyがShallow Copyを行いmyCar 2でSpecialModeを変更したにもかかわらず、myCarとmyCar 2の2つのcarがモードを「Dive」モードに変更していることがわかります.どうしたの?
これがShallow Copyを使用する際の注意点です.
MDNでSpread Operatorドキュメントを表示するときにこのような説明があります.
本書は、Array CopyでSpread Operatorを使用した場合の説明です.以下、Objectです.assign()も同じ概念と言います.
重要なのは、「深さ」(Depth)は1であり、簡単に言えば、上記の例ではmyCarオブジェクトの内部プロファイルについてDepthにたとえている.
より容易に理解できるように、最外層のコピーのみをコピーすることは、浅いコピーとみなすことができる.
このように見ることができますが、もっと詳しく理解するには
Shallow Copyは、元のオブジェクトのプロパティ値を新しいオブジェクトに正確にコピーします.
ただし、約propertyの値が元のタイプではなく、「オブジェクト」の場合、オブジェクトのアドレスがコピーされます.🔍
すなわち、コピーされたオブジェクトは元のオブジェクトと同じpropertyと値を有するが、アドレスコピーされたpropertyは新しい形式ではなく「同じ」(オブジェクトのメモリアドレス)を共有する.
📍 参照タイプのコピー-深度コピー
深度コピーは、元のオブジェクトを完全にコピーします.
さっき見たように、Shallow Copyは致命的なトラップではなく、新しいメモリスペースを増やすことで作成されます.
たとえば、先ほどのShallow Copyの場合と比較して、Deep Copyは次のような内部構造を持っています.
Propertyにオブジェクトやメソッドなどの追加のDepthがある場合でも、完全に独立した新しいメモリ領域を得ることができます.
深度コピーを実現する方法は、次のとおりです.
1️⃣. JSON.parse()とJSON.stringgify()関数の使用
/**
* Deep Copy(깊은 복사) - JSON 함수를 이용
*/
let myFruit = {
name: "Apple",
price: 1000,
characteristic: {
favor: "Sweet",
},
};
let myFruit2 = JSON.parse(JSON.stringify(myFruit));
myFruit2.characteristic.favor = "Very Sweet";
console.log(myFruit); // { name: 'Apple', price: 1000, characteristic: { favor: 'Sweet' } }
console.log(myFruit2); // { name: 'Apple', price: 1000, characteristic: { favor: 'Very Sweet' } } 🔍
最後に,myFruitとmyFruti 2は完全に分離して用いられているが,特徴(オブジェクトProperty)PropertyのDepthは1ではない.前述のJSON関数を使用する場合、次のような問題が発生します.
/**
* Deep Copy - JSON 함수 사용시 function 누락 현상
*/
let myObj = {
name: "obj",
sayHi: function () {
console.log("Hello Javascript");
},
};
let copyMyObj = JSON.parse(JSON.stringify(myObj));
console.log(myObj.sayHi); // [Function: sayHi]
console.log(copyMyObj.sayHi); // undefined 🔍
このほか、オブジェクトツリーにループ参照がある場合、stringpyメソッドでループ構造をJSONに変換するタイプエラーが発生します.2️⃣. LodashのCloneDeep関数の使用/**
* Deep Copy(깊은 복사) - lodash 에 cloneDeep 함수를 이용
* - lodash 라이브러 import 필요
*/
const _ = require("lodash");
let myFruit = {
name: "Apple",
price: 1000,
characteristic: {
favor: "Sweet",
},
sayHi: function () {
console.log("과일이 인사를 하네요.");
},
};
let myFruit2 = _.cloneDeep(myFruit);
console.log(myFruit);
// {
// name: 'Apple',
// price: 1000,
// characteristic: { favor: 'Sweet' },
// sayHi: [Function: sayHi]
// }
console.log(myFruit2);
// {
// name: 'Apple',
// price: 1000,
// characteristic: { favor: 'Sweet' },
// sayHi: [Function: sayHi]
// }
3️⃣. ダイレクトインプリメンテーション /**
* Deep Copy - 재귀를 이용한 직접 구현
*/
function clone(source) {
var target = {};
for (let i in source) {
if (source[i] != null && typeof source[i] === "object") {
target[i] = clone(source[i]); // resursion
} else {
target[i] = source[i];
}
}
return target;
}
let myFruit = {
name: "Apple",
price: 1000,
characteristic: {
favor: "Sweet",
},
sayHi: function () {
console.log("과일이 인사를 하네요.");
},
};
const myFruit2 = clone(myFruit);
console.log(myFruit);
// {
// name: 'Apple',
// price: 1000,
// characteristic: { favor: 'Sweet' },
// sayHi: [Function: sayHi]
// }
console.log(myFruit2);
// {
// name: 'Apple',
// price: 1000,
// characteristic: { favor: 'Sweet' },
// sayHi: [Function: sayHi]
// }
n/a.結論
[TMI]
結局、今までJSは「コピー」を間違って知っていました(私のように)😁) 多くの人がDepthが1のデータだけをShallow Copyとしているので、「ん~異常なし」と考えているのであれば、本当に重要なのはDeep Copyです.
それは知る必要があるようです.
オブジェクトをコピーする場合、「Shallow Copyは良くない」と無条件に判断するのは間違いです.場合によっては、Shallow Copyだけでオブジェクトをコピーすることができ、Deep Copyでデータを注意深くコピーする必要がある場合があります.
それを正しく判断して使うことが大切です.
このテーマを調べたところ、以下のようにコピーが重要だと思う理由が書かれていました.
予知できないエラーを最小限に抑える.
同意します.JS自体は,実行時言語であるため,途中で思いがけない場所でデータが操作される可能性があり,デバッグ時にプログラムが大きくなるほど発見が困難になる.当初は今回まとめたShallow CopyやDeep Copyを考えた方が良いと思います.
反復可能なオブジェクトについて説明します.
リファレンス
Reference
この問題について([JS]深放射&浅放射), 我々は、より多くの情報をここで見つけました https://velog.io/@youngminss/JS-깊은-복사-얕은-복사テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol