JavaScript에서 Object 복사하기

JavaScript에서 Object 복사하기

Front-end developer WONISM
Interested in ReactJS, RxJS and ReasonML.

객체를 참조하는 복사

객체가 아닌 Primitive의 값을 복사하려면 단순히 b = a와 같이 변수에 복사하고자 하는 변수를 대입하면 된다.
하지만, 객체에서는 b = a와 같은 방법을 사용할 수 없다. 객체를 참조하는 복사가 이루어지기 때문이다.
따라서, b = a를 수행한 뒤 a가 수정이 되면, b까지 수정되는 것을 볼 수 있다.

const obj1 = { a: 42 };
const obj2 = obj1;

obj2.a = 5;

console.log(obj1); // { a: 5 }

얕은 복사하기(Shallow copy)

객체를 복사하기 위한 방법으로 다양한 방법이 있다.
Object.prototype.constructor메소드를 사용하거나, Lodash, Ramda같은 라이브러리를 사용하는 것이다.

constructor 메소드 사용하기

function copyObject(obj) {
  if (obj === null || typeof obj === 'object') {
    return obj;
  }

  const copiedObject = obj.constructor();

  for (let key in obj) {
    if (obj.hasOwnProperty(prop)) {
      copiedObject[key] = obj[key];
    }
  }
}

const obj1 = { a: 42 };
const obj2 = copyObject(obj1);

obj2.a = 5;

console.log(obj1); // { a: 42 }

위와 같이, 인자가 null이 아닌 객체일 경우, constructor메소드로 해당 객체와 똑같은 객체를 생성한다. 그 다음, hasOwnProperty를 통해 해당 객체가 인자로 넘긴 프로퍼티를 가지고 있는지 체크하고, 이에 맞는 프로퍼티에 같은 값을 할당한다.

참고 : Spread operator 사용하기

ES2015...를 사용해도 된다.

const obj1 = { a: 42 };
const obj2 = { ...obj1 };

obj2.a = 5;

console.log(obj1); // { a: 42 }

Lodash & Ramda

import fp from 'lodash/fp';
import R from 'ramda';

const obj1 = { a: 42 };
const obj2 = fp.clone(obj1);

const obj3 = { a: 42 };
const obj4 = R.merge({}, obj3);

Ramdaclone이란 메소드가 있지만, Ramdaclone은 깊은 복사를 수행한다.
따라서 얕은 복사의 목적으로 객체를 복사하고자 할 때는 merge가 훨씬 빠르다.

깊은 복사하기(Deep copy)

위 얕은 복사에서는 객체의 한 프로퍼티 값이 객체이고, 해당 객체가 수정이 되면, 원본의 프로퍼티 값이 수정이 되는 문제가 있다.
이를 피하려면 깊은 복사를 수행한다. 깊은 복사는 얕은 복사와 마찬가지로 constructor메소드를 사용하거나, 외부 라이브러리를 사용하는 방법이 있다.

constructor 메소드 사용하기

function copyObject(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  const copiedObject = obj.constructor();

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copiedObject[key] = copyObject(obj[key]);
    }
  }

  return copiedObject;
}

const foo = {
  deep: {
    key: 'value'
  },
  shallow: false
};
const bar = copyObject(foo);

bar.deep.key = 'other value';

console.log(foo); // { deep: { key: 'value' }, shallow: false }
console.log(bar); // { deep: { key: 'other value' }, shallow: false }

Lodash & Ramda

import fp from 'lodash/fp';
import R from 'ramda';

const obj1 = { a: 42 };
const obj2 = fp.cloneDeep(obj1);

const obj3 = { a: 42 };
const obj4 = R.clone(obj3);