자바스크립트에서 값은 원시값과 참조값으로 나뉜다.
원시값은 값을 복사할 때 복사된 값을 다른 메모리에 할당하기 때문에 원래의 값과 복사된 값이 서로에게 영향을 미치지 않는다.
let a = 1;
let b = a;
b = 2;
console.log(a); // 1
console.log(b); // 2
참조값은 변수가 객체의 주소를 가리키는 값이기 때문에 복사된 값(주소)이 같은 값을 가리킨다.
let a = {number : 1};
let b = a
b.number = 2;
console.log(a); // {number : 2}
console.log(b); // {number : 2}
이러한 객체 특성으로 인하여 객체를 복사하는 방법에 두가지가 있다.
얕은 복사란 객체를 복사할 때, 원래 값과 복사된 값이 같은 참조를 가리키고 있는 것을 말한다.
객체 안에 객체가 있을 경우 한 개의 객체라도 원본 객체를 참조하고 있다면 이를 얕은 복사라고 한다.
첫번째 요소로 들어온 객체에 다음 인자로 들어온 객체를 복사해준다.
const obj = {
a : 1,
b : {
c : 2
},
};
const copied = Object.assign({}, obj);
copied.b.c = 3;
console.log(obj === copied) // false
console.log(obj.b.c === copied.b.c) // true
const obj = {
a : 1,
b : {
c : 2
}
};
const copied = {...obj}
copied.b.c = 3;
console.log(obj === copied) // false
console.log(obj.b.c === copied.b.c) // true
객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말한다.
const obj = {
a: 1,
b: {
c: 2,
},
};
function copyObj(obj) {
const result = {};
for (let key in obj) {
if (typeof obj[key] === 'object') {
result[key] = copyObj(obj[key]);
} else {
result[key] = obj[key];
}
}
return result;
}
const copiedObj = copyObj(obj);
copiedObj.b.c = 3
console.log(obj.b.c === copiedObj.b.c) //false
JSON.stringify( )는 객체를 json 문자열로 변환하는데, 이 과정에서 원본 객체와의 참조가 모두 끊어진다.
객체를 json 문자열로 변환 후 JSON.parse( )를 이용해 다시 자바스크립트 객체로 만들어주면 깊은 복사가 된다.
단, 이 방법은 다른 방법에 비해 속도가 매우 느리다.
const obj = {
a: 1,
b: {
c: 2,
},
};
const copiedObj = JSON.parse(JSON.stringify(obj));
copiedObj.b.c = 3
console.log(obj.b.c === copiedObj.b.c) //false
Lodash를 사용할 경우 깊은 복사를 간단히 해결할 수 있다.
const obj = {
a: 1,
b: {
c: 2,
},
};
const copiedObj = _.cloneDeep(obj);
copiedObj.b.c = 3
console.log(obj.b.c === copiedObj.b.c) //false