본문 바로가기
자바 스크립트

자바스크립트 참조에 의한 객체복사

by y00ns00 2020. 12. 6.

객체와 원시타입의 근본적인 차이 중 하나는 객체는 차몾에 의해(by reference)저장되고 복사된다는 점.

원시값(문자열,숫자,불린값) 은 '값 그래도' 저장 할당되고 복사

 

 

let message = "Hello!";
let phrase = message;

두개의 독립된 변수에 각각 문자열 "Hello!"가 저장

 

변수에는 객체가 그대로 저장되는 것이 아니라 객체가 저장되어있는 메모리 주소인 객체에대한 참조 값이 저장된다.

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

 

 

참조에 의한 비교

객체 비교시 동등 연산자 == 와 일치 연산자 === 는 동일하게 동작한다.

비교시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환한다.

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

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

 

 

객체 복사, 병합과 Obejct.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(dest, [src1, src2, src3...])

문법과 동작방식

- 첫번째 인수 dest는 목표로 하는객체

- 이어지는 src1,...,srcN는 복사하고자 하는 객체 ... 은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타낸다.

객체 src1,...,srcN의 프로퍼티를 dest에 복사 dest를 제외한 인수(객체)의 프로퍼티 전부가 첫 번째 인수(객체)로 복사

- 마지막으로 dest를 반환

 

assign 메서드를 사용해 여러 객체를 하나로 병합하는 예시

(목표 객체(user)에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워 진다.)

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

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

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

 

 

모든 프로퍼티가 빈 배열에 복사되고 변수에 할당

let user = {
  name: "John",
  age: 30
};

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

 

 

 

중첩 객체 복사

프로퍼티는 다른 객체에 대한 참조 값 일 수도 있다.

 

이런경우 clone.sizes = user.sizes로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없다.

user.sizes는 객체이기 때문에 참조값이 복사된다.

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[key]의 각값을 검사하면서 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야한다. 이런 방식을 깊은복사(deep cloning)라고 한다.

자바스크립트 라이브러리 lodash의 메서드인 .cloneDeep(obj)를 사용하면 이 알고리즘을 직접구현하지 않고 처리할수 있다.

 

 

요약

객체는 참조에 의해 할당되고 복사된다.

변수엔 '객체' 자체가 아닌 메모리상의 주소인'참조'가 복사된다.

복사된 참조를 이용한 모든작업(추가,삭제)는 동일한 객체를 대상으로 이뤄진다.

 

객체의 '진짜 복사본'을 만드렵면 얕은복사를 가능하게 해주는 Object.assign 이나 '깊은복사'를 가능하게 해주는 .cloneDeep(obj)를 사용한다.

(얕은 복사본은 중첩 객체를 처리하지 못한다.)

 

 

출처 : ko.javascript.info/object-copy

댓글