객체와 원시 타입의 근본적인 차이 중 하나는 객체는 '참조에 의해(by reference)' 저장되고 복사된다는 것이다.
변수엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소'인 객체에 대한 '참조 값'이 저장된다.
let user = {
name: "John"
};
객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고 객체는 복사되지 않는다.
let user = { name: "John" };
let admin = user; // 참조값을 복사함
객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있다.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
객체 복사, 병합과 Object.assign
복제가 필요한 상황이라면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해
원시 수준까지 프로퍼티를 복사하면 된다.
let user = {
name: "John",
age: 30
};
let clone = {}; // 새로운 빈 객체
// 빈 객체에 user 프로퍼티 전부를 복사해 넣는다.
for (let key in user) {
clone[key] = user[key];
}
// 이제 clone은 완전히 독립적인 복제본이 되었다.
clone.name = "Pete"; // clone의 데이터를 변경한다.
alert( user.name ); // 기존 객체에는 여전히 John이 있다.
Object.assign을 사용하는 방법도 있다.
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// permissions1과 permissions2의 프로퍼티를 user로 복사한다.
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
Object.assign을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있다.
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
중첩 객체 복사
프로퍼티는 다른 객체에 대한 참조 값일 수도 있다.
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)를 사용하면 된다.
이때 얕은 복사본은 중첩 객체를 처리하지 못한다는 점을 기억해야 한다.
'Web > Javascript' 카테고리의 다른 글
'new' 연산자와 생성자 함수 (0) | 2020.05.31 |
---|---|
메서드와 'this' (0) | 2020.05.31 |
객체 기초 (0) | 2020.05.31 |
자바스크립트 기초 (0) | 2020.05.22 |
객체지향(OOP) 프로그래밍 (0) | 2018.01.17 |