September 5, 2021
객체와 원시 타입의 근본적인 차이 중 하나는 객체는 ‘참조에 의해(by reference)’ 저장되고 복사된다는 것입니다.
원시값(문자열, 숫자, 불린 값)은 ‘값 그대로’ 저장·할당되고 복사되는 반면에 말이죠.
예시:
목표 객체(user
)에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워 집니다.
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // user = { name: "Pete" }
Object.assign
을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있습니다.
let user = {
name: "John",
age: 30
};
*let clone = Object.assign({}, user);*
예시를 실행하면 user
에 있는 모든 프로퍼티가 빈 배열에 복사되고 변수에 할당됩니다.
지금까진 user
의 모든 프로퍼티가 원시값인 경우만 가정했습니다. 그런데 프로퍼티는 다른 객체에 대한 참조 값일 수도 있습니다. 이 경우는 어떻게 해야 할까요?
아래와 같이 말이죠.
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
clone.sizes = user.sizes
로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없습니다. user.sizes
는 객체이기 때문에 참조 값이 복사되기 때문입니다. clone.sizes = user.sizes
로 프로퍼티를 복사하면 clone
과 user
는 같은 sizes를 공유하게 됩니다.
아래와 같이 말이죠.
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, 같은 객체입니다.
// user와 clone는 sizes를 공유합니다.
user.sizes.width++; // 한 객체에서 프로퍼티를 변경합니다.
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할 수 있습니다.
이 문제를 해결하려면 user[key]
의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 합니다. 이런 방식을 '깊은 복사(deep cloning)'라고 합니다.
깊은 복사 시 사용되는 표준 알고리즘인 Structured cloning algorithm을 사용하면 위 사례를 비롯한 다양한 상황에서 객체를 복제할 수 있습니다.