얕은 복사(Shallow Copy), 깊은 복사(Deep Copy)

HeumHeum2·2021년 12월 1일
1
post-thumbnail

JavaScript에서 객체나 배열을 자주 복사한다. 내가 사용하는 복사가 얕은 복사인지 깊은 복사인지 자세하게 알기 위해 구글링을 통해 답변을 찾았다.

❓깊은 복사

내가 주로 자주 사용하는 복사 방법은 Object.assign({}, obj), {...obj} 이 두 방식이 있다.

const obj = {id: 1, test: {name: "hello"} };

const clone1 = Object.assign({}, obj);
clone1.id = 2;

const clone2 = { ...obj };
clone2.id = 3;

console.dir(obj, {depth: null});   // {id: 1, test: {name: "hello"}}
console.dir(clone1, {depth: null}) // {id: 2, test: {name: "hello"}}
console.dir(clone2, {depth: null}) // {id: 3, test: {name: "hello"}}

id 값을 변경할 때 서로 다른 것을 확인할 수 있어 이게 깊은 복사구나 싶었다. 제대로 찾아보기 전까진..

const obj = {id: 1, test: {name: "hello"} };

const clone1 = Object.assign({}, obj);
clone1.test.name = "world";

const clone2 = { ...obj };
clone2.test.name = "new world";

console.dir(obj, {depth: null});   // {id: 1, test: { name: "new world" }}
console.dir(clone1, {depth: null}) // {id: 2, test: { name: "new world" }}
console.dir(clone2, {depth: null}) // {id: 3, test: { name: "new world" }}

위 코드에서 독립적인 형태를 원했다. 하지만 결과는 그렇지 않았다.

객체 안에 객체 또는 배열인 경우 값이 아닌 주소를 참조하는 방식인 듯 했다. 그렇기에 얉다해서 얉은 복사인 것 같다.

그렇다면 깊은 복사는 어떻게 만들까?

❗️깊은 복사

JSON 객체의 메소드 이용

JSON.stringif 와 JSON.parse를 이용해서 사용하는 방법이다.

const obj = {id: 1, test: {name: "hello"} };

const clone = JSON.parse(JSON.stringify(obj));
clone.test.name = "world";

console.dir(obj, {depth: null});   // {id: 1, test: {name: "hello"} };
console.dir(clone, {depth: null}}; // {id: 1, test: {name: "world"} };

객체를 문자열로 변환 후, 다시 객체로 변환되었기에 이전 객체에 대한 주소 참조가 없어진다. 그렇기에 깊은 복사가 가능했는데, 문제는 깊은 복사가 불가능한 타입들이 꽤 많다는 단점이 있다. 그 예로 함수, Date 객체, 정규표현식, Infinity 등 데이터가 복사되지 않고 유실되어버린다.

재귀함수 이용

function deepCopy(obj) {
  const clone = {};
    for(let key in obj) {
     typeof obj[key] === "object" && obj[key] !== null
      ? clone[key] = deepCopy(obj[key])
      : clone[key] = obj[key];
    }
  return clone;
}

const obj = {id: 1, test: {name: "hello"} };
const clone = deepCopy(obj);
clone.test.name = "world";

console.dir(obj, {depth: null});   // {id: 1, test: {name: "hello"} };
console.dir(clone, {depth: null}}; // {id: 1, test: {name: "world"} };

깊게 들어가서 하나하나 복사하는 방법이다. 객체가 깊으면 깊을 수록 시간복잡도가 늘어난다는 단점이 있다.

lodash의 cloneDeep()

가장 쉬운 방법은 누군가 만들어 놓은 걸 가져다가 사용하는 방법이다. 이미 Lodash를 사용하고 있으면 더 좋다.

const lodash = require('lodash');

const obj = {id: 1, test: {name: "hello"} };
const clone = lodash.cloneDeep(obj);
clone.test.name = "world";

console.dir(obj, {depth: null});   // {id: 1, test: {name: "hello"} };
console.dir(clone, {depth: null}}; // {id: 1, test: {name: "world"} };

Simple하다. 단점으로는 해당 라이브러리를 사용하고 있지 않다면 고려해봐야한다.

참조

https://leonkong.cc/posts/js-deep-copy.html

profile
커피가 본체인 개발자 ☕️

0개의 댓글