JavaScript 객체 복사하기 ( 얕은복사, 깊은복사 )

이번에는 자바스크립트 객체를 복사하는 방법에 대해 살펴보겠습니다.

객체 복사에는 얕은복사 (Shallow Copy)가 있고, 깊은 복사 (Deep Copy) 가있습니다.

얕은 복사는 참조하는 것으로서 복사하여 만들어진 객체를 수정하여도 기존 객체도 함께 수정됩니다.

즉 같은것을 참조하고 있는 것이고 깊은 복사는 다른 객체로 생성되어 수정하여도 기존 객체는 영향이 없습니다.

 

복사에 방법에는 크게 3가지로 나눌 수 있습니다.

 

1. 첫번째는 복제하지 않고 참조하는 변수만 만들어 얕게 복사합니다.

let sub = {sub: 'sub', time: 1000}
let A = {name: 'Aiden', class: 'A', email: 'aiden@naver.com', item: sub};
let B = A;

console.log(Object.is(A,B)) // true;
console.log(Object.is(A.item, B.item)) // true;
B.name = 'newAiden';

console.log(A.name) // 'newAiden'

 

B는 A를 얕은복사 한 것으로 같은 것을 가리킵니다.

즉 B를 수정하여도 A가 수정되게됩니다.

 

2. 두 번째는 Object.assign입니다. 대표 객체는 깊은 복사 하지만 하위 객체는 얕은 복사 합니다.

let sub = {sub: 'sub', time: 1000}
let A = {name: 'Adien', class: 'A', item: sub};
let B = Object.assign({}, A);

console.log(Object.is(A,B)); // false
console.log(Object.is(A.item, B.item)); // true

대표 객체인 A와 B는 다르다고 하지만 하위 객체는 같은 값입니다.

 

 

3. 세 번째는 대표 객체뿐만 아니라 하위 객체도 깊은 복사 하는 방법입니다.

  이 방법에는 3가지가 있습니다.

 

- JSON.stringify()

let sub = {sub: 'sub', time: 1000}
let A = {name: 'Adien', class: 'A', item: sub};
let B = JSON.parse(JSON.stringify(A));

console.log(Object.is(A,B)); // true
console.log(Object.is(A.item, B.item)); // true

JSON.stringify()는 객체를 json 문자열로 변환하는데 그 과정에서 객체와의 참조가 모두 끊어진다.

이 방법은 사용하기는 쉽지만 다른 방법에 비해 아주 느리다고 알려져 있다.

 

- 재귀 함수를 이용한 복사

const mainObj = {
	a : 1,
    o : {
    	b : 2
    }
};

function deepCopyObj(targetObj) {
    const result = {};
    
    for (let key in targetObj) {
    	if (typeof targetObj[key] === 'object') {
        	result[key] = deepCopyObj(targetObj[key]);
        } else {
        	result[key] = targetObj[key];
        }
    }
    
    return result;
}

const deepCopiedObj = deepCopyObj(mainObj);

console.log(Object.is(mainObj, deepCopiedObj)) // false;
console.log(Object.is(mainObj.o.b, deepCopiedObj.o.b)) // false;

 

- 라이브러리 사용

lodash 라이브러리를 사용하면 깊은 복사를 더 쉽게 할 수 있다.

const deepCopiedObj = _.cloneDeep(mainObj);

console.log(Object.is(deepCopiedObj, mainObj)); // false