-
JS deep copy 방법javascript 2021. 6. 6. 00:25
시작하며
js sortable 라이브러리를 사용하는 중 deep copy(깊은 복사)를 필요로 하는 상황이 있었다. 그런데 spread 문법을 통해 (완벽한) deep copy가 가능할 거라고 생각했었는데 이 부분에서 오류가 있었다는 것을 알게 되었고, deep copy에 대해 정리해보기로 하였다.
총 4가지 방법으로 (1. json, 2. spread, 3. custom function, 4. lodash) deep copy하는 방법을 소개하고, 어떤 상황에서 각 방법을 사용하면 좋을지 간단히 정리했다.참고로 deep copy(깊은 복사)와 shallow copy(얕은 복사)의 차이에 대해서는 JS deep copy(깊은 복사) vs shallow copy(얕은 복사) 에서 정리하겠다.
1. json문법을 사용한 deep copy
const newObject = JSON.parse(JSON.stringify(oldObject));
object를 stringify -> parse 과정을 통한 deep copy인데 함수를 포함하는 경우에는 복사되지 않는다.
ex)
- 함수를 포함하는 경우:
const oldObject = {a:'1',b: () => {console.log('hi');}}; const newObject = JSON.parse(JSON.stringify(oldObject)); console.log(newObject); // {a: "1"}
2. spread를 사용한 deep copy
ES6 spread 문법을 사용해서도 deep copy가 가능하나 1 level(dimension)의 array, object에서만 deep copy가 가능하다.
ex)
- 1차원 array에서는 deep copy 가능:
const foo = [1,2,3]; const bar = [...foo]; // deepcopy
- 2~n차원 array에서는 shallow copy가 됨:
const foo = [[1,2],3]; const bar = [...foo]; foo[0].push(3); console.log(bar); // [[1,2,3],3]
이후 소개할 lodash의 deepCopy 방법보다 성능은 더 좋아서 1차원의 object, array만 다루는 상황이면 사용해볼 만한 것 같다.
lodash deepCopy vs spread deepCopy benchmark
Benchmark: Lodash cloneDeep VS spread operator - MeasureThat.net
measurethat.net
3. deep copy 함수 만들어 사용하기
reduce와 재귀를 통해서 2차원 이상의 object, array에서도 새로운 객체를 반환하게끔 함수를 만들어 deep copy할 수 있다.
다음은 stack overflow출처 코드로 object, array, Date 객체까지 deep copy한 결과를 반환해주는 함수다.Deep copy in ES6 using the spread syntax
I am trying to create a deep copy map method for my Redux project that will work with objects rather than arrays. I read that in Redux each state should not change anything in the previous states.
stackoverflow.com
function deepCopy(obj) { if(typeof obj !== 'object' || obj === null) { return obj; } if(obj instanceof Date) { return new Date(obj.getTime()); } if(obj instanceof Array) { return obj.reduce((arr, item, i) => { arr[i] = deepCopy(item); return arr; }, []); } if(obj instanceof Object) { return Object.keys(obj).reduce((newObj, key) => { newObj[key] = deepCopy(obj[key]); return newObj; }, {}) } }
이후 소개할 lodash를 사용한 deep copy와 비교했을때, lodash를 사용하지 않는 환경이라면 이 방법을 사용해도 좋을 것 같다. deep copy만을 위해 사이즈 큰 lodash를 import 하기에는 비효율적이라고 생각한다.
몇 가지 모듈 크기 비교 시각화 4. lodash의 cloneDeep 사용하기
lodash에서 cloneDeep이라는 함수로 간단하게 deep copy를 할 수 있다.
가장 간단하고 명확한 방법으로 대체적으로 해당 방법을 추천한다.import _ from "lodash"; const newObj = _.cloneDeep(obj);
마치며
개인적으로는 deep copy를 사용할 때 항상 lodash를 사용할 것 같다. lodash의 다양한 함수들을 기존부터 사용하다보니 프로젝트를 구성할 때 항상 포함시킬 것이고, 성능 측면에서는 다른 방법이 좋을 수 있지만 사용 가능한 범위가 넓고 간단하다는 점이 나에게는 가장 큰 장점으로 느껴진다.
'javascript' 카테고리의 다른 글
JS e.preventDefault()와 e.stopPropagation() (0) 2021.06.20 JS Optional Chaining (0) 2021.06.20 JS deep copy(깊은 복사) vs shallow copy(얕은 복사) (0) 2021.06.07