JavaScript에서 중첩된 객체를 비교하는 작업은 까다로운 작업입니다. 특히 React 생명주기 함수에서 prevState와 현재 state를 비교할 때, 비교해야 하는 값이 중첩된 객체 또는 배열인 경우 많은 어려움에 직면합니다.
저는 JavaScript의 중첩된 객체와 배열을 공부하면서 두 개의 중첩된 객체를 비교하는 방법으로 JSON.stringify가 좋은 방법인줄 알았습니다. 하지만, 객체에 대해 좀 더 공부하면서 JSON.stringify를 사용해야 하는 경우도 있고 사용하지 말아야 하는 경우가 있다는 것을 알게 되었습니다.
이번 포스팅은 중첩된 객체를 JSON.parse 및 JSON.stringify를 사용하여 복사하였을 경우 어떠한 문제가 발생하는지 알아보도록 합니다.
얕은 복사의 문제점
다음은 스프레드 연산자( ...
)를 사용하여 객체를 복사 후 속성의 값을 변경하는 코드입니다.
const obj = {
name : [{
first: 'Kang',
last: 'Jae Seong'
}]
};
let cloneObj = [...obj.name];
cloneObj[0].first = 'Kim';
console.log(obj);
console.log(cloneObj);
실행 결과
얕은 복사가 수행되었기 때문에 복사된 객체의 속성을 변경하면, 원본 객체의 속성도 변경되는 문제가 발생합니다.
다음 코드는 JSON.parse와 JSON.stringify를 사용하여 객체를 복사 후 값을 변경합니다.
const obj = {
name : [{
first: 'Kang',
last: 'Jae Seong'
}]
};
let cloneObj = JSON.parse(JSON.stringify(obj));
cloneObj.name[0].first = 'Kim';
console.log(obj);
console.log(cloneObj);
실행 결과
JSON.parse와 JSON.stringify를 사용하면 객체를 깊이 복사합니다. 즉, 중첩된 객체의 값을 변경해도 원래 객체의 속성 값은 변경되지 않습니다.
JSON.parse와 JSON.stringify의 문제점
JSON.parse(JSON.stringify(Object))
를 사용하면 얕은 복사에 대한 문제는 해결되지만 또 다른 문제를 직면하게 됩니다.
다음과 같이 객체에 함수가 존재하는 경우입니다.
const obj = {
name : [{
first: 'Kang',
last: 'Jae Seong'
}],
printConsole: function(name) {
console.log(name[0]);
}
};
let cloneObj = JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(cloneObj);
실행 결과
JSON은 <key>:<value> 쌍에서 value가 함수인 경우 복사를 생략합니다.
해결 방법
객체 또는 배열을 복사하는 방법 중 최고의 해결 방법은 Lodash 라이브러리의 _.cloneDeep
함수를 사용하는 것입니다.
cloneObj = _.cloneDeep(obj);
외부 라이브러리를 사용하는데 어느 정도 자원과 비용을 소모하는 문제가 있지만, Lodash는 지금까지 나와있는 방법 중 가장 훌륭한 솔루션입니다.
참고
'JavaScript > JavaScript 문법' 카테고리의 다른 글
[JavaScript]객체(Object)가 비어있는지 체크하는 방법 (2) | 2021.12.02 |
---|---|
[JavaScript]JSON parse 와 JSON stringify 차이 (0) | 2021.12.02 |
[JavaScript]console 객체 사용 방법 (0) | 2021.11.29 |
[JavaScript]Object.assign() 함수와 Object.create()의 차이점 (0) | 2021.11.16 |
[JavaScript]배열에서 임의의 요소를 가져오는 방법 (0) | 2021.11.10 |
댓글