Javascript

객체 - 참조에 의한 객체 복사

big whale 2021. 7. 3. 15:09

객체와 원시 타입의 근본적인 차이

객체를 변수에 저장하면

1. 객체는 메모리 내 어딘가에 저장되고

2. 변수에는 객체가 메모리 내 어디에 위치하는지 알려주는 참조값이 저장된다.

 

따라서 객체가 할당된 변수를 복사할 때는 객체의 참조값이 복사되고 객체는 복사되지 않는다.

따라서 하나의 객체에 접근하거나 조작할 땐 여러 변수를 사용할 수 있다.

let user = { name: 'John'};

let admin = user; // 변수 admin에 user에 저장된 객체의 참조 값을 복사함

admin.age: 30; // 'admin' 참조 값에 의해 변경됨

alert(user.age); // 30이 출력됨, 'user' 참조 값을 이용해 변경사항을 확인함

 

 

참조에 의한 비교

 

두 변수가 같은 객체를 참조하는 경우 ==,=== 둘 다 true 반환

let a = {};
let b = a; // 참조에 의한 복사

alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true

 

이번에는 두 객체가 둘 다 비어있는 객체지만, 두 객체는 서로 다른 참조값을 가지기 때문에 동등(==),일치(===)하지 않다.

let a = {};
let b = {};

alert( a == b ); // false
alert( a === b ); // false

 

객체 복사

Object.assign 사용

Object.assign(객체1,객체2,객체3, ... )

객체1 - 목표로 하는 객체

객체2, 객체3 - 복사하고자 하는 객체

 

사용 예시

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
let permissions3 = { name: "Janna" };

// permissions1과 permissions2의 프로퍼티를 user로 복사합니다.
Object.assign(user, permissions1, permissions2, permission3);

// now user = { name: "Janna", canView: true, canEdit: true }

여기서 name같이 복사할 객체에 동일한 이름을 가진 프로퍼티가 있는 경우에는 기존 값이 덮어씌워 진다. 

 

중첩 객체 복사

 

프로퍼티가 다른 객체에 대한 참조 값인 경우

Object.assign : 얕은 복사

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, 같은 객체입니다.

// user와 clone는 sizes를 공유합니다.
user.sizes.width++;       // 한 객체에서 프로퍼티를 변경합니다.
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할 수 있습니다.

user객체의 sizes는 객체의 참조값이다.

따라서 프로퍼티를 복사하는 것 만으로는 객체를 복사할 수 없다. Ojbect.assign으로 복사해도 참조값이 복사돼서 같은 sizes를 공유하게 된다.

 

이 문제를 해결하려면 user[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 한다.

이런 방식을 '깊은 복사(deep cloning)'라고 한다.

자바스크립트 라이브러리 lodash의 메서드 _.cloneDeep(obj)를 사용해서 깊은 복사를 처리할 수 있다.