원시값(문자열, 숫자, 불린값)은 '값 그대로' 저장 및 할당되고 복사되는 반면에, 객체는 '참조에 의해(by reference)' 저장되고 복사된다.
즉, 변수엔 객체가 그대로 저장되는 것이 아니라,
객체가 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장된다.
따라서 객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고, 객체는 복사되지 않는다.
EX.
let user = { name : "Lee" };
let admin = user; // 참조값 복사
위 예시에서 변수는 두 개(admin
, user
)지만, 각 변수엔 동일 객체에 대한 참조값이 저장된다.
따라서 객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있다.
let user = { name : "Lee" };
let admin = user; // 참조값 복사
admin.name = 'Yujin'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Yujin'이 출력된다.
객체 비교 시 동등 연산자 ==
와 일치 연산자 ===
는 동일하게 동작한다.
비교 시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환한다.
두 변수가 같은 객체를 참조한다면 일치·동등 비교 모두에서 참이 반환된다.
하지만 독립된 두 빈 객체를 일치·동등 비교한다면 거짓이 반환된다.
객체간의 대소 비교나 원시값과의 비교에선 객체가 원시형으로 변환된다.이러한 비교가 필요한 경우는 매우 드물긴 하다. (대개 코딩 실수 때문에 이런 비교가 발생한다.)
객체가 할당된 변수를 복사하면 동일한 객체에 대한 참조 값이 하나 더 만들어진다는 걸 다뤘다.
기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면 어떻게 할까?
사실 객체를 복제해야 할 일은 거의 없지만, 정말 복제가 필요한 상황이라면,
let user = {
name: "Lee",
age: 23
};
let clone = {}; // 새로운 빈 객체 생성
// 순회하며 프로퍼티들 모두 복사
for(let key in user) {
clone[key] = user[key];
}
// 이제 clone은 user와는 완전히 독립적인 user의 복제본이다.
📌 문법
Object.assign(dest, [src1, src2, src3, ...])
dest
: 목표로 하는 객체src1, ... srcN
: 복사하고자 하는 객체. 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다.- 객체
src1, ... srcN
의 프로퍼티를dest
에 복사한다.dest
를 제외한 인수(객체)의 모든 프로퍼티가 첫 번째 인수(객체)에 복사된다.- 마지막으로
dest
를 반환한다.
assign
메서드를 사용해 여러 객체를 하나로 병합해보자.
let user = { name: "Lee" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// permissions1과 permissions2의 프로퍼티를 user로 복사
Object.assign(user, permissions1, permissions2);
// now user = { name: "Lee", canView: true, canEdit: true }
단, 목표 객채(user
)에 동일한 이름을 가진 프로퍼티가 있는 경우,
기존 값이 덮어씌워진다.
Object.assign
을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있다.
지금까지 user
의 모든 프로퍼티가 원시값인 경우만 가정했다.
그런데 프로퍼티는, 다른 객체에 대한 참조 값일 수도 있다.
let user = {
name: "Peter",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
clone.sizes = user.sizes
로 될까?이 경우, 프로퍼티를 복사하는 것만으로는 객체를 복사할 수 없다!
user.sizes
는 객체이기 때문에 참조 값이 복사되기 때문이다. 이렇게 되면 clone
과 user
는 독립적이지 않은, 같은 sizes를 공유하게 된다.
user[key]
의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야한다.
이런 방식을 깊은 복사(deep cloning)이라 한다.
📌 깊은 복사 시 사용되는 표준 알고리즘: Structured cloning algorithm
📌 lodash의 메서드인 _.cloneDeep(obj): 이 알고리즘을 직접 구현하지 않고도 깊은 복사 처리 가능
이 글은 https://ko.javascript.info/ 를 참고하여 작성하였습니다.