얕은 복사 vs 깊은 복사 + 함정
원시값 Copy
원시값은 복사할 때 복사된 값을 다른 메모리에 할당하기에 원래의 값과 복사된 값이 서로 영향을 미치지 않습니다.
const a = 1;
let b = a;
b = 2;
console.log(a); // 1
console.log(b); // 2
객체 (참조) Copy
참조값은 변수가 객체의 주소를 가리키는 값이 되기 때문에 복사된 값(주소)이 같은 값을 가리키게 됩니다.
const c = { number: 1 };
let d = c;
d.number = 2;
console.log(c.number); // 2
console.log(d.number); // 2
const e = [1, 2, 3];
let f = e;
f[0] = 10;
console.log(e); // [10, 2, 3]
console.log(f); // [10, 2, 3]
얕은 복사 Shllow: 얕은 copy 복사
대입 연산자를 이용하여 변수를 copy 할 때 객체의 주소 값을 넣어 복사하는 것을 얕은 복사라고 한다.
이렇게 될 경우 두 변수 모두 값에 접근하여 객체의 상태를 변경 할 수 있다. ( => 수정 가능하다)
깊은 복사 Deep: 깊은 copy 복사
깊은 복사된 객체는 객체안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말한다.
한 데이터의 공유가 아닌, 똑같은 구조의 객체를 하나 더 생성하여 따로 사용하고자 할 때 사용하는 Copy 방법
1. Object.assign() assign: 맡기다 배치하다
Object.assign은 첫번째 요소로 들어온 객체에 다음인자로 들어온 객체를 복사해준다.
빈 Object에다가 복사를 하려는 Object를 병합한다. 그러면 형태는 originObj이지만 실제로는 빈 Object와 originObj가 병합된 새로운 Object가 반환된다.
실제 객체는 다른 곳에 있고 변수는 다른 곳에 있는 객체의 주소 값을 저장해 참조한다.
변수에 변경 사항을 지시한다면 주소의 값으로 찾아가 그 객체의 상태를 변경한다.
근데!!! 객체 안의 객체도 마찬가지다.. 그도 다른 객체에 할당하고 주소 값을 가지게 된다.
※ 여기에 Object.assign()의 함정이 숨어 있다!!
const obj = {
a: "a",
num: {
one: 1,
two: 2,
},
};
const shllowCopy = Object.assign({}, obj);
console.log(shllowCopy); //{ a: 'a', num: { one: 1, two: 2 }}
console.log(shllowCopy === obj); // false
console.log(shllowCopy.num === obj.num); // true
shllowCopy.a = "A";
console.log(shllowCopy); //{ a: 'a', num: { one: 1, two: 2 }}
console.log(obj);
shllowCopy.num.one = "one";
console.log(obj); //{ a: 'a', num: { one: 'one', two: 2 } }
obj === shllowCopy false 이지만
obj.num === shllow.num 은 true가 나온다.
객체 안의 객체는 같은 주소를 참조 하고 있는 것이다.
Object.assign()은 깊은 복사인가 얕은 복사인가.. 그 중간인가 ㅠㅠㅠ
2. 전개 연산자 ( Spread Operation)
전개 연산자도 마찬가지이다.
const shllowCopy2 = { ...obj };
console.log(shllowCopy2); //{ a: 'a', num: { one: 1, two: 2 }}
console.log(shllowCopy2 === obj); // false
console.log(shllowCopy2.num === obj.num); // true
shllowCopy2.a = "A";
console.log(shllowCopy2); //{ a: 'a', num: { one: 1, two: 2 }}
console.log(obj);
shllowCopy2.num.one = "one";
console.log(obj); //{ a: 'a', num: { one: 'one', two: 2 } }
깊은 복사가 된 것은 제일 바깥의 Depth뿐이다.
※ 객체 안의 객체가 있을 경우 한개의 객체라도 원본 객체를 참조하고 있다면 이것은 얕은 복사이다!!
찐 깊은 복사
객체 안의 객체가 있을 때 그 안의 객체 모두!! 원본 객체와의 참조가 완전히 끊어진 객체!!
1. 재귀 함수를 이용한 복사
객체의 프로퍼티는 변수고
결국에 변수 안에 원시 값이 담기는 것이다.
원시 값은 항상 깊은 복사 이므로
각 객체 내의 프로퍼티를 모두 깊은 복사로 따와버린다!! 자기 자신을 호출 함으로 써!! 모든 객체를!!
function deepCopy(obj) {
const deep = {};
for (let key in obj) {
if (typeof obj[key] === "object") {
deep[key] = deepCopy(obj[key]);
} else {
deep[key] = obj[key];
}
}
return deep;
}
const copiedObj = deepCopy(obj);
console.log(copiedObj); // { a: 'a', b: { c: 2 } }
console.log(copiedObj === obj); // false
copiedObj.b.c = "c";
console.log(copiedObj); // { a: 'a', b: { c: 'c' } }
console.log(obj); // { a: 'a', b: { c: 2 } }
2. JSON.stringify()
JSON.stringify()로 객체를 json 문자열로 반환하는 과정에서 원본 객체와의 참조가 모두 끊어진다!!
이 후 JSON.parse()로 자바스크립트 객체로 바꿔주면 깊은 복사가 된다
... 매우 느리다고 알려져 있다.
copiedObj = JSON.parse(JSON.stringify(obj));
console.log(copiedObj); // { a: 'a', b: { c: 2 } }
console.log(copiedObj === obj); // false
copiedObj.b.c = "c";
console.log(copiedObj); // { a: 'a', b: { c: 'c' } }
console.log(obj); // { a: 'a', b: { c: 2 } }
3. lodash 라이브러리 사용
// import _ from "lodash"
copiedObj = _.cloneDeep(obj);
console.log(copiedObj); // { a: 'a', b: { c: 2 } }
console.log(copiedObj === obj); // false
copiedObj.b.c = "c";
console.log(copiedObj); // { a: 'a', b: { c: 'c' } }
console.log(obj); // { a: 'a', b: { c: 2 } }
console.timeEnd(" ");
[Javascript] 얕은 복사, 깊은 복사
자바스크립트에서 값은 원시값과 참조값으로 나뉜다. 원시값 Number String Boolean Null Undefined 참조값 Object Symbol 원시값은 값을 복사 할 때 복사된 값을 다른 메모리에 할당 하기 때문에 원래의 값과
velog.io