[JavaScript] 객체 복사 (얕은 복사, 깊은 복사)

MINEW·2022년 7월 5일
0

객체 복사의 문제점

  • Object의 값을 복사할 때는 객체 자체가 아닌, 메모리 주소가 복사됩니다.
  • 복사한 객체의 속성을 변경하면, 기존 객체의 속성까지 변경되는 문제가 발생합니다.
const original = {
  first: 1,
  second: 2,
};

const copy = original;

delete original.first; // 1번) original의 key값만 삭제

console.log(original); // 2번) original의 결과는 { second: 2 } 로 잘나온다
console.log(copy); // 3번) 그러나, copy의 결과도 { second: 2 } 로 나온다. 즉, original 객체만 건드렸는데 copy 객체까지 영향을 받는다.

객체 복사 해결 방법1: 얕은 복사

  1. 얕은 복사1: for문으로 일일이 복사
const original = {
  first: 1,
  second: 2,
};

const copy = {}; // 1번) copy에 빈 객체 생성

for (const key in original) { // 2번) original에 있는 값을 copy에 일일이 복사해 넣는다
  copy[key] = original[key];
}

delete original.first; // 3번) original 객체를 건드려도

console.log(original); // 4번) 결과가 { second: 2 } 로 잘나온다
console.log(copy); // 5번) 결과가 { first: 1, second: 2 } 로 잘나온다
  1. 얕은 복사2: Object.assign({}, original)
const original = {
  first: 1,
  second: 2
};

const copy = Object.assign({}, original); // 1번) (왼쪽요소에, 오른쪽요소를 덮어씌워서) -> 왼쪽요소를 반환하는 메서드

delete original.first; // 2번) original 객체를 건드려도

console.log(original); // 3번) 결과가 { second: 2 } 로 잘나온다
console.log(copy); // 4번) 결과가 { first: 1, second: 2 } 로 잘나온다
  1. 얕은 복사3: spread 연산자 { ...original }
const original = {
  first: 1,
  second: 2
};

const copy = { ...original }; // 1번) original 내에 있는 모든 값을 copy에 넣는다

delete original.first; // 2번) original를 건드려도

console.log(original); // 3번) 결과가 { second: 2 } 로 잘나온다
console.log(copy); // 4번) 결과가 { first: 1, second: 2 } 로 잘나온다

얕은 복사의 문제점

  • 객체 속성값(value)으로 또다른 객체나 배열이 있으면, 기존에 발생했던 문제가 똑같이 발생합니다.
const original = {
  first: 1,
  second: 2,
  third: { // 1번) 속성값으로 객체를 넣고
    number: 3
  },
};

const copy = { ...original }; // 2번) 얕은 복사를 하면

delete original.third; // 3번) 이때는 문제없이 original의 third만 삭제되지만
delete original.third.number; // 4번) original의 third안의 객체를 건드리면

console.log(original); // 5번) 결과가 { first: 1, second: 2, third: {} } 로 잘나온다
console.log(copy); // 6번) 그러나 copy의 결과도 { first: 1, second: 2, third: {} } 로 나온다. original만 건드렸는데, copy까지 같이 바뀐다.

객체 복사 해결 방법2: 깊은 복사 (얕은 복사에서 나타나는 문제 해결)

  1. 깊은 복사1: for문으로 일일이 복사 + 재귀함수 추가 실행
const original = {
  first: 1,
  second: 2,
  third: {
    number: 3
  },
};

function change(obj) {
  const result = {};
  for (const key in obj) {
    if (typeof obj[key] === "object") { // 1번) value값으로 객체를 받으면
      result[key] = change(obj[key]); // 2번) 재귀함수를 통해 함수를 추가로 실행
    } else {
      result[key] = obj[key];
    }
  }
  return result;
};

const copy = change(original);

delete original.third.number; // 3번) original 객체를 건드려도

console.log(original); // 4번) 결과가 { first: 1, second: 2, third: {} } 로 잘나온다
console.log(copy); // 5번) 결과가 { first: 1, second: 2, third: { number: 3 } } 로 잘나온다

  1. 깊은 복사2: JavaScript 객체를 -> JSON 문자열로 변환 후 -> JSON 문자열을 다시 javascript 객체로 변환
const original = {
  first: 1,
  second: 2,
  third: {
    number: 3
  },
};

const copy = JSON.parse(JSON.stringify(original)); // 1번) 이때 원본객체와의 참조가 끊긴다

delete original.third.number; // 2번) original를 건드려도

console.log(original); // 3번) 결과가 { first: 1, second: 2, third: {} } 로 잘나온다
console.log(copy); // 4번) 결과가 { first: 1, second: 2, third: { number: 3 } } 로 잘나온다

참고: 배열 복사

  1. 배열 복사의 문제점
    - 객체 복사와 같은 문제가 발생합니다.
const original = [1, 2, 3, 4, 5, 6];
const copy = original;
console.log(original); // [ 1, 2, 3, 4, 5, 6 ]
console.log(copy); // [ 1, 2, 3, 4, 5, 6 ]

copy.shift();
console.log(original); // [ 2, 3, 4, 5, 6 ]
console.log(copy); // [ 2, 3, 4, 5, 6 ]
  1. 해결 방법1: 얕은 복사
const oriShallow = [1, 2, 3, 4, 5, 6];
const copyShallow = [ ...oriShallow ];
console.log(oriShallow); // [ 1, 2, 3, 4, 5, 6 ]
console.log(copyShallow); // [ 1, 2, 3, 4, 5, 6 ]

copyShallow.shift();
console.log(oriShallow); // [ 1, 2, 3, 4, 5, 6 ]
console.log(copyShallow); // [ 2, 3, 4, 5, 6 ]
  1. 얕은 복사의 문제점
    - 2차원 배열에서 객체 얕은 복사와 같은 문제가 발생합니다.
const oriShallowProblem = [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]];
const copyShallowProblem = [ ...oriShallowProblem ];
console.log(oriShallowProblem); // [ [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
console.log(copyShallowProblem); // [ [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]

copyShallowProblem[0].shift();
console.log(oriShallowProblem); // [ [ 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
console.log(copyShallowProblem); // [ [ 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
  1. 해결 방법2: 깊은 복사
const oriDeep = [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]];
const copyDeep = JSON.parse(JSON.stringify(oriDeep));
console.log(oriDeep); // [ [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
console.log(copyDeep); // [ [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]

copyDeep[0].shift();
console.log(oriDeep); // [ [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
console.log(copyDeep); // [ [ 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ], [ 1, 2, 3, 4, 5, 6 ] ]
  1. 배열 -> 객체 안에 복사 (spread 연산자)
    - 배열을 객체로 펼치면, 객체 안에 인덱스가 key, 배열요소가 value 로 들어갑니다.
const names = ['길동', '철수', '영희', '무명']; // 1번) 배열을
const obj = { ...names }; // 2번) 전개 연산자를 사용해 -> 객체 안에 복사하면
console.log(obj); // { '0': '길동', '1': '철수', '2': '영희', '3': '무명' } // 3번) 인덱스가 key값으로, 배열요소가 value값으로 들어간다
  1. 객체 -> 배열 안에 복사 (TypeError)
    - 배열은 객체로 펼칠 수 있지만, 객체는 배열로 펼칠 수 없습니다.
const topic = {
  name: '모던 자바스크립트',
  language: 'JavaScript', 
};

const newArray = [ ...topic ]; // TypeError 발생

profile
JS, TS, React, Vue, Node.js, Express, SQL 공부한 내용을 기록하는 장소입니다

0개의 댓글