shallow copy , deep copy


shallow copy


繰り返し文でオブジェクトの値をコピーします.オブジェクトの値がオブジェクトの場合、オブジェクトのアドレスがコピーされます.
以前は原始資料型と参考資料型を学び、原始資料型の複製値、参考資料型の複製アドレスを学んだ.
//원본이 원시자료형인 경우
let primitive = 10;
let copiedPri = primitive;

copiedPri = 20; //copiedPri에 20 재할당
copiedPri; //20
primitive; //10 

//원본이 참조자료형인 경우
const arr = [1,2,3];
const copiedArr = arr; //arr의 주소가 복사된다.

copiedArr.push('추가');
copiedArr; //[1,2,3,'추가']
arr; //[1,2,3,'추가']
そこで、参考資料型の「値」だけをコピーする方法も学びました.
値はslice()、assign(ターゲット、ソース)、spread演算子のみでコピーできます.

Array.prototype.slice

const arr = [1,2,3];
const copiedArr = arr.slice();

copiedArr.push('추가');
copiedArr; //[1,2,3,'추가']
arr; //[1,2,3]
sliceメソッドを使用すると、「値」がコピーされたと判断できます.したがって、コピーにエンティティを追加または削除しても、元のエンティティには影響しません.
ただし、次の場合、コピーを変更すると元のコピーも変更されます.
const arr = [1,2,3,[4]];
const copiedArr = arr.slice();

copiedArr[3].push('추가');
copiedArr; //[1,2,3,[4,'추가']]
arr; //[1,2,3,[4,'추가']]
上の状況で確認したようにArrayprototype.sliceのソースがネストされた構造(配列に配列がある構造)の場合、ネストされたエンティティを「値」にコピーするのではなく、アドレスがコピーされます.すなわち,sliceは浅いコピー(浅いコピー)を実行し,すべての値を独立してコピーすることはできない.

spread operator


ES 6構文を使用して追加された拡張オペレータは、比較的簡単にコピーできます.
拡張オペレータが呼び出されると、内部で反復-ループが実行されます.オブジェクトに対して繰り返し文を実行できることは、オブジェクトに[Symbol.iterator]Propertyがあることを意味します.つまり、オブジェクトに[Symbol.iterator]属性がある場合、そのオブジェクトは繰り返し文を実行できます.
const a = [1,2,3];
const b = [...a];
b; //[1,2,3]

//내면에서 일어나는 과정
if(![Typeof(a) is Iterable)){
  throw TypeError
}

const b = [];
for(let i=0;i<a.length;i++){
  b.push(b[i]);
}
オブジェクトに[Symbol.iterator]propertyがあると判断した場合、forは文を繰り返し、要素を1つずつ移動します.移入要素の深さは1−dptである.
したがって、slice演算子とspread演算子は、内部で重複文を実行し、配列またはオブジェクトが段落である場合、その段落が指すアドレスをコピーします.

Object.assign

//Copy
const obj = {a:1};
const copy = Object.assign({},obj);

console.log(copy); //{a:1}
console.log(obj===copy); //false

//Merge -기존 객체에 합치기
const obj1 = {a:1};
const obj2 = {b:2};
const obj3 = {c:3};

const merge1 = Obejct.assign(obj1,obj2,obj3);

console.log(merge1); //{a:1, b:2, c:3}
console.log(obj1); //{a:1, b:2, c:3}

//Merge -빈 객체에 합치기
const obj4 = {d:4};
const obj5 = {e:5};
const obj6 = {f:6};

const merge2 = Object.assign({},obj4,obj5,obj6);

console.log(merge2); //{d:4, e:5, f:6}
console.log(obj4); //{d:4}

//Nested Object가 있는 객체 복사하기
const original = {
  name: 'kim',
  age: 20,
  city: 'seoul',
  todos: ['study','exercise','clean','wash']
}
const copied = Object.assign({},original);

copied.todos.push('추가');
console.log(copied.todos); //['study','exercise','clean','wash', '추가']
console.log(original.todos); //['study','exercise','clean','wash', '추가']
Object.assign(ターゲット、ソース)もプロパティの値をコピーするので、ソースオブジェクトのキー値がオブジェクトへの参照(オブジェクトまたは配列の場合)である場合、参照がコピーされます.
言い換えれば、slice、spread構文、Object.assignはいずれも浅いコピーを実行します.

deep copy


浅いコピーからNestedオブジェクトへの参照をコピーするのとは異なり、Nestedオブジェクトは新しいメモリ領域を取得し、コピーに新しい参照を持たせます.
キー値が参照の場合、参照のみコピーできますか?そうではありません.限られているが最も簡単な方法はJSONオブジェクトを使用することである.

JSON.parse & JSON.stringify



JSON.stringgifyを使用して配列を文字列に変更し、JSONを再開します.parseを使用してオブジェクトを置き換えます.
ここで文字列に変換する理由は、JavaScriptでは文字列が他の言語とは異なり、可変属性を持つ元のデータ型(primitive datatype)であるため、参照ではなく値そのものが格納されるためである.後で並べ替えるとnested objectにも新しい参照があります.配列を一瞬凍結(文字列)して融解(配列)したいなら、簡単なはずです.

したがって、上記の手順でアレイをコピーすると、レプリカで変更しても元のアレイは変更されないことを確認できます.
プロセスを一つ一つまとめてみましょう.
  • スタック内の文字列ラベル付き空間は、「[1,2,3,4]」に割り当てられる.
  • スタックに解析ラベルが付いた空間にオブジェクトへの参照が格納されます.ここで、参照は既存のarrの参照とは異なります.
  • 従ってarrとparsedは異なるアドレスを参照する.しかしながら、この方法の欠点は、JSONオブジェクトのstringbyメソッドがfunctionでundefinedとして処理されるなど、JSONオブジェクトで利用可能なデータ型が限られていることである.したがって、jquery、loadshなどの他の方法を用いることができる.
    参考資料:深いコピーと浅いコピーの深い物語
    Javascript: shallow and deep copy