자바스크립트 원시타입과 참조타입(객체)가 있는데, 원시타입의 경우 값이 복사되지만 참조타입의 경우 참조위치가 복사된다.
객체에서 완전한 값(원시타입)을 복제하기 위해선 const a = {}; const b = a;
와 같이 단순하게 변수에 대입하는 것이 아닌 다른 방법이 필요하다.
Object.assign()
,spread operator
등을 통해 객체안의 값을 복사하는 방법- 한단계 까지만 복사하기 때문에 중첩객체(객체안에 객체가 있을 경우) 의 경우 여전히 원본 객체를 참조하는 문제가 있다.
let user = {
name: "Jinyoung",
sizes: {
height: 200,
weight: 100,
},
};
// shallow copy 1. for
const cloneShallow1 = {};
for (let key in user) {
cloneShallow1[key] = user[key];
}
// shallow copy 2. Object.assign
const cloneShallow2 = Object.assign({}, user);
// shallow copy 3. Spread Operator
const cloneShallow3 = { ...user };
cloneShallow1 === user; // false;
cloneShallow1.size === user.size; // true;
- 중첩객체의 경우에도 참조위치가 다른 객체로 복사하는 완전한 복사의 방법.
- 중첩객체이더라도 원시타입이 나올때까지 탐색한다음 원시타입을 복사한다.
- 재귀함수를 활용한 방법,
JSON.stringify()
, lodash 라이브러리의cloneDeep
메소드 등이 있다.
// deep copy 1. recursive function
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
const result = Array.isArray(obj) ? [] : {};
for (let key of Object.keys(obj)) {
result[key] = deepClone(obj[key]);
}
return result;
}
const cloneDeep1 = deepClone(user);
// deep copy 2. JSON method
const cloneDeep2 = JSON.parse(JSON.stringify(user));
// deep copy 3. Lodash library
const lodashCopy = require("lodash.clonedeep");
const cloneDeep3 = lodashCopy(user);
추가 내용
JSON.stringify()
의 경우 아래와 같이undefined
,function
,symbol
을null
로 변환하기 때문에 주의가 필요하다.
console.log(JSON.stringify({ x: [10, undefined, function () {}, Symbol("")] }));
// expected output: "{"x":[10,null,null,null]}"`
- 객체간의 복사가 완전하지 않으면 불변성에 어긋나게 되고, 객체간에 서로 영향을 줄 수 있기 때문에 완전한 복사가 필요하다.
- 하지만 깊은 복사의 경우 그만큼 메모리 자원을 사용하기 때문에 이를 인지하고 사용해야 한다.