JavaScript/JavaScript 문법

[JavaScript]JSON.parse 및 JSON.stringify를 객체 복사에 사용하면 안되는 이유

DevStory 2021. 12. 2.

JavaScript에서 중첩된 객체를 비교하는 작업은 까다로운 작업입니다. 특히 React 생명주기 함수에서 prevState와 현재 state를 비교할 때, 비교해야 하는 값이 중첩된 객체 또는 배열인 경우 많은 어려움에 직면합니다.

 

저는 JavaScript의 중첩된 객체와 배열을 공부하면서 두 개의 중첩된 객체를 비교하는 방법으로 JSON.stringify가 좋은 방법인줄 알았습니다. 하지만, 객체에 대해 좀 더 공부하면서 JSON.stringify를 사용해야 하는 경우도 있고 사용하지 말아야 하는 경우가 있다는 것을 알게 되었습니다.

 

이번 포스팅은 중첩된 객체를 JSON.parseJSON.stringify를 사용하여 복사하였을 경우 어떠한 문제가 발생하는지 알아보도록 합니다.

 


얕은 복사의 문제점

다음은 스프레드 연산자( ... )를 사용하여 객체를 복사 후 속성의 값을 변경하는 코드입니다.

const obj = {
  name : [{
    first: 'Kang',
    last: 'Jae Seong'
  }]
};

let cloneObj = [...obj.name];

cloneObj[0].first = 'Kim';

console.log(obj);
console.log(cloneObj);

실행 결과

얕은 복사가 수행되었기 때문에 복사된 객체의 속성을 변경하면, 원본 객체의 속성도 변경되는 문제가 발생합니다.

 

다음 코드는 JSON.parseJSON.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.parseJSON.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는 지금까지 나와있는 방법 중 가장 훌륭한 솔루션입니다.


참고

https://medium.com/@saumya.verma9/why-json-parse-and-json-stringify-should-not-be-used-for-deep-cloning-191b38026cc7

 

Why JSON.parse and JSON.stringify should not be used for deep cloning

Manipulating nested json objects is a tricky business especially when comparin nextProps and this.props with react js.

medium.com

 

https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript

 

What is the most efficient way to deep clone an object in JavaScript?

What is the most efficient way to clone a JavaScript object? I've seen obj = eval(uneval(o)); being used, but that's non-standard and only supported by Firefox. I've done things like obj = JSON.parse(

stackoverflow.com

 

반응형

댓글