프로필사진
JavaScript의 얕은 복제 & 깊은 복제

2020. 1. 30. 17:45🔴 FE/JavaScript

300x250

흔히 하는 실수 '=' 연산자 사용

let origin = { num : 1 }
let clone = origin
origin.num = 2

console.log(clone) // { "num" : 2 }

 

객체는 '참조타입(reference type)'이기 때문에 객체를 '='로 복사하면 값이 아니라 메모리 주소값 참조를 복사한다.
즉, clone과 origin는 같은 메모리를 사용한다는 것이다.
그러므로 콘솔에 찍어보면 하나의 객체가 2개의 변수에 의해서 공유되고 있는걸 확인할 수 있다.
(하나의 변수를 통해 값을 바꿨지만, 다른 변수의 값도 함께 바뀌었다)

console.log(origin === clone)

따라서, 객체를 비교할 때 참조가 같은지 비교하는 '===, =='로 비교해보면 'true'라는 결과가 나온다.

얕은 복제 (Shallow Clone)

1. Object.assign(target, ...sources)

let clone = Object.assign({}, origin)

console.log(origin === clone) // false

해당 함수를 쓰면 첫번째 인자({})로 두번째 인자의 속성들을 복사할 수 있다
비교를 해보면 'false'라고 뜨며, 값을 바꿔도 서로 영향을 주지 않는다.

BUT, 그 값이 단순 속성이 아니라 객체나 배열리면 여전히 서로 영향을 끼친다

let origin = {
	innerObj : {
    	x : 1,
        y : 2
    }
}

만약 origin 속의 innerObj속성이 객체라면?

console.log(origin.innerObj === clone.innerObj) // true

같은 주소값을 참조하고 있는 것을 확인할 수 있다.
이는 Object.assign()메서드가 "객체 트리의 최상위 레벨의 속성만 복사"하기 때문에 이런 현상이 나타나는 것이다.

2. ... (Spread Operator)

let clone = {...origin}

console.log(origin.innerObj === clone.innerObj) // true

Spread Operator를 사용하여 의도적으로 얕은 복제를 할 수 있다.

깊은 복제 (Deep Clone)

앞서 살펴봤듯이, 얕은 복제는 최상위의 속성만 복제하기 때문에 '깊은' 복제를 하려면 객체 트리의 제일 아래까지 복제해줘야 한다는 것을 알 수 있다. 재귀 함수를 만들어 최말단까지 복제할 수 있지만, 직접 구현하는 것보다 'lodash'오픈소스를 사용하는 것이 더 편리하다.

https://lodash.com/docs/4.17.15#clone

 

Lodash Documentation

_(value) source Creates a lodash object which wraps value to enable implicit method chain sequences. Methods that operate on and return arrays, collections, and functions can be chained together. Methods that retrieve a single value or may return a primiti

lodash.com

1. _.clone(value)

lodash에서 제공하는 얕은 복제 함수이다.

import * as _ from 'lodash';

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

2. _.cloneDeep(value)

깊은 복제를 위해 우리는 cloneDeep함수를 사용하면 된다. 이 함수는 재귀적으로 value를 복제해준다.

import * as _ from 'lodash';

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

+ 이 외에도 "JSON.parse(JSON.stringify(origin))" 으로 깊은 복제를 할 수 있다고 하지만
string으로 바꿨다가 다시 parse할 때 만약 function이 속성으로 있다면 적합하지 않다고 한다.


참고:

https://velog.io/@ashnamuh/Javascript-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%9D%98-%ED%95%A8%EC%A0%95

https://www.daleseo.com/js-objects-clone/

300x250