- 객체와 원시 타입의 근본적인 차이 중 하나는 객체는 ‘참조에 의해(by reference)’ 저장되고 복사된다는 것입니다.
let message = "Hello!";
let phrase = message;
- 그런데 객체의 동작방식은 이와 다릅니다.
- 변수엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장됩니다.
- 그림을 통해 변수 user에 객체를 할당할 때 무슨 일이 일어나는지 알아봅시다.
let user = {
name: "John"
};
- 객체는 메모리 내 어딘가에 저장되고, 변수 user엔 객체를 '참조’할 수 있는 값이 저장됩니다.
- 따라서 객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고 객체는 복사되지 않습니다.
let user = { name: "John" };
let admin = user; // 참조값을 복사함
- 변수는 두 개이지만 각 변수엔 동일 객체에 대한 참조 값이 저장되죠.
따라서 객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있습니다.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
참조에 의한 비교
- 객체 비교 시 동등 연산자 ==와 일치 연산자 ===는 동일하게 동작합니다.
- 비교 시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환하죠.
let a = {};
let b = a; // 참조에 의한 복사
alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true
- 두 객체 모두 비어있다는 점에서 같아 보이지만, 독립된 객체이기 때문에 일치·동등 비교하면 거짓이 반환됩니다.
let a = {};
let b = {}; // 독립된 두 객체
alert( a == b ); // false
객체 복사, 병합과 objecct.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(dest, [src1, src2, src3...])
- 첫 번째 인수 dest는 목표로 하는 객체입니다.
- 이어지는 인수 src1, ..., srcN는 복사하고자 하는 객체입니다. ...은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타냅니다.
- 객체 src1, ..., srcN의 프로퍼티를 dest에 복사합니다. dest를 제외한 인수(객체)의 프로퍼티 전부가 첫 번째 인수(객체)로 복사됩니다.
- 마지막으로 dest를 반환합니다.
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 }
요약
- 객체는 참조에 의해 할당되고 복사됩니다.
- 변수엔 ‘객체’ 자체가 아닌 메모리상의 주소인 '참조’가 저장됩니다.
- 따라서 객체가 할당된 변수를 복사하거나 함수의 인자로 넘길 땐 객체가 아닌 객체의 참조가 복사됩니다.
- 그리고 복사된 참조를 이용한 모든 작업(프로퍼티 추가·삭제 등)은 동일한 객체를 대상으로 이뤄집니다.
- 객체의 '진짜 복사본’을 만들려면 '얕은 복사(shallow copy)'를 가능하게 해주는 Object.assign이나 '깊은 복사’를 가능하게 해주는 _.cloneDeep(obj)를 사용하면 됩니다.
- 이때 얕은 복사본은 중첩 객체를 처리하지 못한다는 점을 기억해 두시기 바랍니다.
'모던 javascript 튜토리얼' 카테고리의 다른 글
메서드와 this (0) | 2022.06.25 |
---|---|
가비지 컬렉션 (0) | 2022.06.24 |
객체 (0) | 2022.06.22 |
폴리필 (0) | 2022.06.21 |
테스트 자동화와 Mocha (0) | 2022.06.20 |