자바스크립트에서 객체원시타입의 근본적인 차이중 하나는 참조에 의해 저장되고 복사된다는 것 입니다.

해당 문장 이해하기 어려우니 예시를 보면서 알아보겠습니다...!

원시값 예시

let message = "Hello!";
let copy = message;

예시를 실행하면 두 개의 독립된 변수에 각각 "Hello!" 가 저장됩니다.

하지만 객체는 다르게 동작합니다!
예시를 보면서 알아봅시다.

let user = {
  name: "John"
};

객체 user를 선언하였습니다.

  1. 자바스크립트는 해당 객체를 메모리 어딘가에 저장합니다.
  2. 변수 user에 객체를 “참조” 할수 있는 값이 저장됩니다.
  3. 변수 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
  1. 객체 a 는 메모리에 저장되고 참조 값을 받는다.
  2. 객체 b 는 메모리에 저장되고 a와 다른 참조 값을 받는다.
  3. 서로 프로퍼티가 없는것은 같지만 참조값은 다르다!

객체 복사와 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을 사용하는 방법도 있습니다.

사용법

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)을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있으므로 참고하시기 바랍니다.


참고-자바스크립트 튜토리얼

profile
moomoj

0개의 댓글