객체의 얕은 복사는 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조(메모리 내의 같은 값을 가리킴)를 공유하는 복사이다. 따라서 원본이나 복사본을 변경하면 다른 객체 또한 변경될 수 있다. 이러한 동작은 원본과 복사본이 완전히 독립적인 깊은 복사의 동작과 대조적이다.
let obj1 = { name: "Jane", age: "30" };
let obj2 = obj1;
obj2.name = "John";
console.log(obj1, obj2, obj1 === obj2);
그 예시로 이 코드를 들 수 있다.
분명히 obj2의 name을 바꾸었지만 obj1의 name까지 바뀐 것을 알 수 있다.
obj2 = obj1
는 데이터의 같은 주소를 참조하게 되어 이러한 결과를 내게 된다.
const obj = {
a: 1,
b: {
c: null,
d: [1, 2],
},
};
const obj3 = { ...obj };
obj3.a = 6;
obj3.b.c = 1;
obj3.b.d = [1];
console.log(obj);
console.log(obj3);
여기서 문제는 객체 내부의 객체 데이터는 참조 데이터기 때문에 obj와 obj3둘 다 바뀐 것을 볼 수 있다.
객체의 깊은 복사는 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조를 공유하지 않는 복사이다. 따라서 원본이나 복사본을 변경할 때, 다른 객체가 변경되지 않는 것을 보장할 수 있다. 이러한 동작은 원본이나 복사본의 중첩된 속성을 변경하면 다른 객체도 변경될 수 있는 얕은 복사의 동작과 대조적이다. 쉽게 말해서 얕은 복사처럼 참조할 메모리 주소를 공유하지 않고 값만 복사된 아예 다른 객체를 만들어 내는 것이다. 원본과의 참조가 완전히 끊어진 객체로 볼 수 있다.
깊은 복사를 하기 위해서는 몇가지 방법이 존재한다.
const copyObjectDeep = function (target) {
let result = {};
if (typeof target === "object" && target !== null) {
for (const prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
};
const obj = {
a: 1,
b: {
c: null,
d: [1, 2],
},
};
const obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;
console.log(obj);
console.log(obj2);
const obj = {
a: 1,
b: {
c: null,
d: [1, 2],
},
};
const obj4 = JSON.parse(JSON.stringify(obj));
obj4.a = 6;
obj4.b.c = 1;
obj4.b.d = [1];
console.log(obj);
console.log(obj4);
JSON.stringify()
메소드를 통해 객체를 json문자열로 변환한다. 이때 원본 객체와의 참조가 끊어진다고 한다. 그 이후 JSON.parse()
로 다시 원래 객체로 변환한다. 단점으로는 속도가 느리고 JSON.stringify()
는 함수를 undefined
처리한다.
속도 문제는 없는 것 같다.
const obj = {
a: 1,
b: {
c: null,
d: [1, 2],
},
};
const obj5 = Object.assign({}, obj);
obj5.a = 6;
obj5.b.c = 1;
obj5.b.d = [1];
console.log(obj);
console.log(obj5);
Object.assign(생성할 객체, ...복사할 객체)
의 방식으로 사용한다. 이 친구의 문제는 2차원 객체는 얕은 복사가 된다는 것이다.
최근에는 복사를 쓸 일이 없어서 관심 밖에 두고 있었는데 깊은 복사에 대해 오랜만에 개념을 다시 정리하게 되었다. 오늘 수업에서 재귀를 본 것 말고도 다른 방식이 있어서 더 알아 보았는데 앞으로도 알음알음하던 개념들을 다시 정리하면서 가야겠다.