Recent Posts
Recent Comments
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Today
Total
관리 메뉴

DH의 개발 공부로그

[JavaScript] 자바스크립트 얕은 복사 & 깊은 복사 본문

JavaScript

[JavaScript] 자바스크립트 얕은 복사 & 깊은 복사

DeveloperDH 2023. 3. 13. 22:05
728x90

원시 값과 참조 값 알아보기

자바스크립트에는 원시 값참조 값 두가지의 값이 있습니다.
원시 값과 참조 값에 대해서 알고 싶으신 분들은 [JavaScript] 자바스크립트 원시 값과 참조 값!을 확인해주시면 되겠습니다.

원시 값과 참조 값의 복사

원시 값을 복사할 때에 그 값은 또 다른 독립적인 메모리 공간에 할당하고 있기 때문에,
원시 값을 복사 한 후 그 값 수정을 하여도 기존 원시값을 저장한 변수에는 영향을 끼치지 않습니다.
하지만 참조 값은 원시 값과는 다르게 변수가 객체의 주소를 가리키는 값이기 때문에
복사를 하면 복사된 값(주소)이 같은 값을 가리키고 있어서 수정시에는 서로에게 영향을 줄 수 밖에 없는 것 입니다.
한마디로 하나의 주소를 참조해서 원본과 복사한 변수에서 가르키고 있다는 것 입니다.

그렇기 때문에 참조 값의 데이터를 복사 할 때에는 두가지 방식으로 해야하는데 이것이 바로
얕은 복사와 깊은 복사 방법입니다.

얕은 복사(Shallow Copy)

얕은 복사란 쉽게 설명을 하면 가장 상위 객체만 새로 생성되고 내부 객체들은 참조 관계인 경우를 의미합니다.
1뎁스까지만 복사를 하고 더 내부 객체는 참조인 경우입니다. 방법은 다음과 같습니다.

1. Array.prototype.slice()

배열 객체를 얕은 복사하는 방법중 하나로 사용이 되는 slice입니다.
start부터 end 인덱스까지 해당 배열에서 값을 추출하여 새로운 배열로 리턴하는 메소드 입니다.
만약 매개변수를 설정하지 않는다면, 기존 배열의 전체를 얕은 복사합니다.

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
const copy = animals.slice()

copy.push('dog')
console.log(animals)
// ['ant', 'bison', 'camel', 'duck', 'elephant']
console.log(copy);
// ['ant', 'bison', 'camel', 'duck', 'elephant', 'dog']
const number = [1, 2, 3, [4, 5]]
const copyNumber = number.slice()

copyNumber[3].push(6)
console.log(number)
// [1, 2, 3, [4, 5, 6]] 내부의 배열은 참조이기 때문에 원본에도 영향
console.log(copyNumber)
// [1, 2, 3, [4, 5, 6]]

2. Object.assign()

Object.assign은 첫번째 인자로 적어 준 객체에 다음 인자로 들어온 객체를 복사한 후 대상 객체를 반환합니다.

Object.assign(target, ...sources)
const user = { name: 'lee' }
const copyUser = Object.assign({}, user)

copyUser.name = 'kim'
console.log(user)
// {name: 'lee', hobby: 'movie'}
console.log(copyUser)
// {name: 'kim', hobby: 'movie'}

3. Spread 연산자 (전개 연산자)

전개 연산자 역시 얕은 복사입니다. 사용방법은 ...으로 사용할 수 있습니다.

const user = {
    name: 'lee',
    hobby: ['movie', 'soccer']
}
const copyUser = {...user}

copyUser.name = 'kim'
copyUser.hobby.push("coding")
console.log(user)
// {name: 'lee', hobby: ['movie', 'soccer', 'coding']}
console.log(copyUser)
// {name: 'kim', hobby: ['movie', 'soccer', 'coding']}

깊은 복사(Deep Copy)

깊은 복사는 내부 객체까지 모두 새로 생성된 것을 의미합니다

1. JSON.parse && JSON.stringify

첫 번째 방법은 JSON.parseJSON.stringify를 이용하는 방법입니다.
JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어지게 됩니다.
그리고 JSON.parse()를 이용해 다시 원래 객체(자바스크립트 객체)로 변환을 해주는 것 입니다.
이 방법이 가장 간단하고 쉽지만 다른 방법에 비해 느리다는 것과 객체가 function일 경우, undefined로 처리한다는 것이 단점입니다.

const obj = {
  a: 1,
  b: {
    c: 2,
  },
};

const copyObj = JSON.parse(JSON.stringify(obj));

copyObj.b.c = 3

console.log(obj)
// {a: 1, b: {c: 2}}
console.log(copyObj)
// {a: 1, b: {c: 3}}

2. 재귀함수

재귀함수를 이용하여 복사를 하는 방법입니다.
다만 함수를 만들어야 되기 때문에 번거롭고, 복잡하다는 단점이 있습니다.

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)
// {a: 1, b: {c: 2}}
console.log(copyObj)
// {a: 1, b: {c: 3}}

3. 라이브러리 사용

Lodash 라이브러리 사용해서 더 쉽고 안전하게 깊은 복사를 할 수 있습니다.
다만 설치를 해야한다는 번거로움이 있다는 점이 있습니다.

참고

객체의 복사
[Javascript] 얕은 복사, 깊은 복사
Javascript 얕은 복사, 깊은 복사

728x90
Comments