모던 JavaScript 튜토리얼을 따라가면서 정리합니다.
4.2. 참조에 의한 객체 복사
- 객체는 참조에 의해(by reference) 저장되고 복사된다.
- 원시값은 값 그대로 저장, 할당되고 복사된다.
- 변수에는 객체가 그대로 저장되는 것이 아니라, ** 객체가 저장되어 있는 **메모리 주소인 객체에 대한 참조 값이 저장된다.
- 따라서 객체가 할당된 변수를 복사할 때는 객체의 참조 값이 복사되고 객체는 복사되지 않는다.
- 객체에 접근하거나 객체를 조작할 때는 여러 변수를 사용할 수 있다.
참조에 의한 비교
객체 비교 시 동등 연산자
==
와 일치 연산자===
는 동일하게 동작한다.두 변수가 같은 객체를 참조할 때 일치, 동등 비교 모두 참이 반환된다.
독립된 객체이면 일치, 동등 비교 시 거짓이 반환된다.
1 2 3 4
let a = {}; let b = {}; alert (a == b); // false
obj1 > obj2
같은 대소 비교나obj == 5
같은 원시값과의 비교에서는 객체가 원시형으로 변환된다.
객체 복사, 병합과 Object.assign
자바스크립트는 객체 복제 내장 메서드를 지원하지 않는다.
새로운 객체를 만든 후 기존 객체의 프로퍼티를 순회해 원시 수준까지 프로퍼티를 복사하면 된다.
1 2 3 4 5 6 7 8 9 10
let user = { name: "John", age: 30 }; let clone = {}; for (let key in user) { clone[key] = user[key]; }
Object.assign
을 이용한다.1
Object.assgin(dest, [src1, src2, src3...]);
dest
: 목표로 하는 객체src1, src2, ..., srcN
: 복사하고자 하는 객체- 객체
src1, ..., srcN
의 프로퍼티를dest
에 복사한다.dest
를 제외한 인수의 프로퍼티 전부가 첫 번째 인수(객체)로 복사된다. - 마지막으로
dest
를 반환한다.
1 2 3 4 5 6 7 8 9
let user = { name: "John" }; let permission1 = { canView: true }; let permission2 = { canEdit: true }; // permission1과 permission2의 프로퍼티를 user로 복사한다. Object.assign(user, permission1, permission2); // now user = { name: "John", canView: true, canEdit: true };
만약 목표 객체에 동일한 이름을 가진 프로퍼티가 있는 경우 기존 값이 덮어씌워진다.
1 2 3 4
let user = { name: "John" }; Object.assign(user, { name: "Pete" }); // user = { name: "Pete" }
Object.assign
을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있다.1 2 3 4 5 6
let user = { name: "John", age: 30 }; let clone = Object.asign({}, user);
중첩 객체 복사
프로퍼티가 다른 객체에 대한 참조값일 경우 프로퍼티를 복사하는 것만으로 객체를 복사할 수 없다. 프로퍼티의 참조값이 복사되기 때문이다. 즉 복사된 객체와 복사한 객체가 같은 프로퍼티를 공유하게 된다.
이 문제를 해결하기 위해서는 obj[key]
의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용한다. 이런 방식을 깊은 복사(deep cloning)이라고 한다. 이를 직접 구현하거나 자바스크립트 라이브러리 loadash의 _.cloneDeep(obj)
메서드를 사용한다.