TIL 22 | 얕은 복사와 깊은 복사

CHAEIN·2021년 7월 3일
0

JavaScript

목록 보기
22/31
post-thumbnail

참조형 데이터의 경우 원시형 데이터와 달리 참조형 데이터가 할당된 변수를 다른 변수에 그대로 할당하면 데이터 값이 아닌 주소가 복사된다. 이로 인해 한 변수의 데이터를 변경하면 의도치 않게 다른 변수의 데이터도 변경되는 오류가 발생할 수 있다.

const arr1 = [1,2,3]
const arr2 = arr1

arr1.push(4);

console.log(arr1) // [1,2,3,4]
console.log(arr2) // [1,2,3,4] 의도하지 않은 arr2의 배열 데이터도 변경되었다. 이는 arr2에 arr1을 할당할 시 데이터 값이 아닌 데이터 주소가 복사되기 때문이다.

1. 얕은 복사

위의 문제점을 방지하기 위해 배열의 경우 slice() 메소드를 활용할 수 있다.

const arr1 = [1,2,3]
const arr2 = arr1.slice() // arr1과 데이터 값은 동일하지만 새로운 배열을 할당한다. 

arr1.push(4);

console.log(arr1) // [1,2,3,4]
console.log(arr2) // [1,2,3]

객체의 경우 Object.assign() 혹은 for문을 사용하면 복사가 가능하다.

//Objec.assign()을 이용한 복사
const object1 = {
  title : '파이썬 프로그래밍 기초',
  language : 'Python',
}

const object2 = Object.assign({}, object1)

object2.title = '알고리즘의 정석'

console.log(object1) // {title : '파이썬 프로그래밍 기초', language : 'Python',}
console.log(object2) // {title : '알고리즘의 정석', language : 'Python',}
// for 문을 이용한 복사
const object1 = {
  title : '파이썬 프로그래밍 기초',
  language : 'Python',
}

const object2 = {}

for (let key in object1){
  object2[key] = object1.[key];
}

object2.title = '알고리즘의 정석'

console.log(object1) // {title : '파이썬 프로그래밍 기초', language : 'Python',}
console.log(object2) // {title : '알고리즘의 정석', language : 'Python',}

for 문을 이용해서 복사를 할 경우 새로운 객체 복사가 필요할 때마다 매번 같은 for문을 만들어줘야하는 번거로움이 있다. 이를 해결하기 위해 함수를 활용할 수도 있다.

function cloneObject(object){
  let temp = {};
  
  for(let key in object){
    temp[key] = object[key];
  }
  
  return temp;
}

const object1 = {
  title : '파이썬 프로그래밍 기초',
  language : 'Python',
}

const object2 = cloneObject(object1)

object2.title = '알고리즘의 정석'

console.log(object1) // {title : '파이썬 프로그래밍 기초', language : 'Python',}
console.log(object2) // {title : '알고리즘의 정석', language : 'Python',}

배열과 객체 모두 spread 문법을 활용해 복사할 수도 있다.

const arr1 = [1,2,3]
const arr2 = [...arr1]

console.log(arr1[0] === arr2[0]) //false

위와 같은 복사 방법들을 모두 얕은 복사 라고 한다. 그러나 얕은 복사는 완전하지 않다. 객체나 배열 내부에 참조형 데이터가 들어있으면 해당 데이터의 주소값을 복사하는 일이 다시 반복되기 때문이다.

const object1 = {
  title : '파이썬 프로그래밍 기초',
  language : 'Python',
  prerequisite:[]
}

const object2 = cloneObject(object1)
object2.title = '알고리즘의 정석'
object2.prerequisite.push('파이썬 프로그래밍 기초')

// 얕은 복사로 인해 객체 내 요소인 배열은 주소값이 복사되어 object2의 변경이 object1에도 반영되었다.

console.log(object1) // {title : '파이썬 프로그래밍 기초', language : 'Python', prerequisite:['파이썬 프로그래밍 기초']}
console.log(object2) //{title : '알고리즘의 정석', language : 'Python', prerequisite:['파이썬 프로그래밍 기초']}

이러한 문제를 해결하기 위해선 깊은 복사를 활용해야한다.

2. 깊은 복사

깊은 복사는 참조형 데이터 내에 요소로 존재하는 참조형 데이터 값을 새로운 주소로 복사한다.

//재귀함수를 활용한 깊은 복사

function cloneObject(object){
  if(object === null || typeof object !== 'object){
     return object;
  }
  
  let temp;
  if (Array.isArray(object)){
    temp = [];
  } else {
  	temp = {};
  }
  
  for (let key of Object.keys(object)){
    temp[key] = cloneObject(object[key])
  }
  
  return temp;
}    

또는 간편하게 lodash 패키지의 _.cloneDeep(value)을 이용할 수 있다.

import _ from 'lodash'

let objects = [{ 'a': 1 }, { 'b': 2 }];
 
let deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

0개의 댓글