객체와 원시 타입의 근본적인 차이 중 첫 번째는, 객체는 참조에 의해
저장되고 복사된다는 것이다.
원시값(문자열, 숫자, 불린 값)은 값 그대로
저장,할당되고 복사되는 반면에 말이다.
그런데 객체의 동작방식은 이와 다르다.
변수에는 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어 있는 '메모리 주소'인 객체에 대한 '참조 값'이 저장된다.
예시 1)
let user = {
name: "kevin"
};
예시 2)
let a = {};
let b = a; // 참조에 의한 복사
alert( a == b ); // true, 두 변수는 같은 객체를 참조한다.
alert( a === b ); // true
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)
라고 한다.
객체는 참조에 의해 할당되고 복사된다. 변수에는 '객체'
자체가 아닌 메모리상의 주소인 '참조'
가 저장된다. 따라서 객체가 할당된 변수를 복사하거나 함수의 인자로 넘길 땐 객체가 아닌 객체의 참조가 복사된다.
그리고 복사된 참조를 이용한 모든 작업(프로퍼티 추가,삭제 등)은 동일한 객체를 대상으로 이뤄진다.
객체의 진짜 복사본
을 만드려면 얕은 복사(shallow copy)
를 가능하게 해주는 Object.assign
이나 깊은 복사
를 가능하게 해주는 _.cloneDeep(obj)
를 사용하면 된다. 얕은 복사본
은 중첩 객체를 처리하지 못한다는 점을 기억하자!!