JS에서 객체와 배열 복사하기_깊은 복사
객체의 얕은 복사와 깊은 복사 _ 깊은 복사편
얕은 복사 시, 문제점
그러나, 위와 같이 메소드를 활용한 복사에는 중첩 객체(Nested Object)에서 문제점이 발생한다.
ex) 중첩 객체 : 객체 안에 객체, 객체 안에 배열
let obj = { name : 'jun', child : [0,1,2] };
let copy = Object.assign({}, obj);
copy.name = 'kim'
copy.child[0] = 'new';
console.log(obj); // { name : 'jun', child : ['new',1,2] };
console.log(copy); // { name : 'kim', child : ['new',1,2] };
console.log(obj===copy, obj.child===copy.child); // false true
메소드(assign)을 활용하여 객체를 복사할 경우에는 얕은 복사가 되므로, 중첩된 부분인 깊은 곳까지는 복사가 되지 않는 것이다.
따라서, 객체 obj
와 객체 copy
는 다른 곳을 참조하고 있기 때문에 obj===copy
는 false값이 출력되지만, 배열 obj.child
와 copy.child
는 같은 곳을 참조하고 있기 때문에 true값이 출력된다.
1. 메소드를 활용한 깊은 복사하기
얕은 복사 메소드를 활용하여, 깊은 복사가 가능하다. 위의 예시에서 child 는 배열이므로 해당 중첩 계층에서 배열 메소드를 활용하여, 재복사를 해주면 된다.
let obj = { name : 'jun', child : [0,1,2] };
let copy = Object.assign({}, obj); // 얕은 복사
copy.child = obj.child.slice(); // 깊은 복사
console.log(obj===copy, obj.child===copy.child); // false false
copy.name = 'kim'
copy.child[0] = 'new';
console.log(obj); // { name : 'jun', child : [0,1,2] };
console.log(copy); // { name : 'kim', child : ['new',1,2] };
그러나, 이러한 메소드는 obj.child.slice();
와 같이 중첩 시점에서 명시적으로 복사 메소드를 적어주어야 한다는 단점이 존재한다.
2. 재귀 함수로 깊은 복사 직접 구현하기
중첩 객체의 중첩 시점이 어디인지 정확히 파악이 어렵다면, 직접 함수를 만들어주는 방법이 있다. 재귀함수를 통해 최하단 계층까지 내려가 직접 복사를 해주면된다.
const copyObj = (obj) => {
let copy = {};
if (typeof obj === 'object' && obj !== null) {
for (let a in obj) {
if (obj.hasOwnProperty(a)) {
//hasOwnProperty : 객체가 특정 property를 가지고 있으면 true 반환
copy[a] = copyObj(obj[a]);
}
}
} else {
copy = obj;
}
return copy;
};
그러나, 위의 재귀 함수는 객체의 객체는 깊은 복사가 가능하지만, 객체의 배열은 복사가 불가능하다. 예를 들면 이렇다.
let obj = { name : 'jun', child : ['a','b','c'] };
let copy = copyObj(obj);
console.log(copy); // { name : 'jun', child: {0: "a", 1: "b", 2: "c"} }
해당 함수는 객체의 객체에 최적화된 함수이므로 객체의 배열을 객체의 객체로 변환 시켜버렸다. 그렇다면, 객체와 배열에 모두 대응할 수 있는 방법은 없을까?
3. JSON 객체의 메소드를 이용한 깊은 복사하기
JSON.parse()
: JSON 문자열 -> 객체JSON.stringify()
: 객체 -> JSON 문자열
let obj = { name : 'jun', child : ['a','b','c'] };
let copy = JSON.parse(JSON.stringify(obj));
console.log(copy); // { name : 'jun', child: ["a", "b", "c"] }
깊은 복사이므로 당연히 복사본에 대한 수정 시, 원본의 불변성은 유지시킬 수 있다.
const obj = {
name: 'jun',
child : {
first : 'kim',
second : 'young',
}
};
let copy = JSON.parse(JSON.stringify(obj));
console.log(obj === copy); // false;
copy.child.first = 'update';
console.log(obj); // ...first : 'kim' , ...
console.log(copy); // ...first : 'update' , ...
그러나, JSON 객체 메소드 역시 단점이 존재한다. JSON 객체 메소드는 함수와 정규표현식 등 특정 데이터 타입에는 지원이 되지 않는다.
또한, JSON 객체 메소드 자체가 매우 안좋은 성능을 보이고 있으므로 코딩테스트와 같은 효율성을 따질 때는 기피하는 것이 좋다.
4. 남이 만든 것 사용하기
이 방법이 가장 속 편하다... 간단할 것이라고 생각했던 객체 복사는 많은 알고리즘과 예외 처리가 필요하다. 모든 데이터 타입과 모든 계층형 구조에 대응할 수 있는 커스텀 함수를 만들기란 쉽지 않다.
그래서, 남이 잘 만들어놓은 검증된 객체 복사 라이브러리를 사용하는 것이 에러 확률을 줄일 수 있다.
- Immutable.js 사용하기
- JQuery의 $.extend 함수 사용하기
- lodash 라이브러리의 cloneDeep 함수 사용하기
출처
- https://developer.mozilla.org/ko/
- https://www.youtube.com/watch?v=Zm2r5cOFrVU&ab_channel=ZeroChoTVZeroChoTV
- https://www.zerocho.com/category/JavaScript/post/5750d384b73ae5152792188d
Author And Source
이 문제에 관하여(JS에서 객체와 배열 복사하기_깊은 복사), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jun094/JS-객체-배열-복사-하저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)