자바스크립트에서 객체
와 원시타입
의 근본적인 차이중 하나는 참조에 의해 저장되고 복사된다는 것 입니다.
해당 문장 이해하기 어려우니 예시를 보면서 알아보겠습니다...!
원시값 예시
let message = "Hello!";
let copy = message;
예시를 실행하면 두 개의 독립된 변수에 각각 "Hello!" 가 저장됩니다.
하지만 객체는 다르게 동작합니다!
예시를 보면서 알아봅시다.
let user = {
name: "John"
};
객체 user를 선언하였습니다.
let user = { name: "John" };
let admin = user; // 참조값을 복사함
따라서 admin에는 메모리 어딘가에 있는 user의 객체를 복사하는 것이 아닌
메모리에 저장되어있는 user의 참조값
을 복사합니다.
참조값을 복사 한 경우 동등 연산자 ==
과 ===
은 동일하게 동작합니다.
let a = {};
let b = a; // 참조에 의한 복사
alert( a == b ); // true,
alert( a === b ); // true
하지만 똑같은 객체를 각 각 선언한 경우 ==
과 ===
은 동일하지 않습니다.
let a = {};
let b = {}; // 독립된 두 객체 메모리에 저장됨
alert( a == b ); // false
참조값
은 다르다!그러면 자바스크립트에서 객체에 복사는 어떻게 할까요?
기존에 있던 객체와 똑같으면서 독립적인 객체를 만들기가 가능할까요??
방법은 있는데 자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵습니다.
또한 객체를 복사해야 할 일은 거의 없습니다. 대부분 참조에 의한 복사로 해결 가능합니다.
정말 복제가 필요한 상황이라면 새로운 객체를 만든 다음,
기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사하면 됩니다.
예제와 함께 알아봅시다.
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
을 사용하는 방법도 있습니다.
사용법
Object.assign(target, ...sources)
Object.assign 예제
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
Object.assign(user, permissions1, permissions2);
console.log(user) // { name: "John", canView: true, canEdit: true }
target 객체에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워 집니다.
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // user = { name: "Pete" }
Object.assign
을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있습니다.
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
아래 예제 처럼 중첩 객체의 경우 위에 설명한 방법으로 복제하기 어렵습니다.
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
Object.assign
로 중첩 객체 복사 시도해보기
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert(user.sizes === clone.sizes); // true 이므로 참조에 의한 복사
이 문제를 해결하려면 user[key]
의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조 또한 복사해주는 반복문을 사용해야 합니다. 이런 방식을 '깊은 복사(deep cloning)'라고 합니다.
참고
깊은 복사 시 사용되는 표준 알고리즘인 Structured cloning algorithm을 사용하면 위 사례를 비롯한 다양한 상황에서 객체를 복제할 수 있습니다.
자바스크립트 라이브러리 lodash의 메서드인_.cloneDeep(obj)
을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있으므로 참고하시기 바랍니다.