All Articles

wecode 10주차_6일 TIL_깊은 복사와 얕은 복사 그리고 객체의 참조

image.png

한번쯤은 짚고넘어가야 했던 부분인데 이제서야 정리해본다!
깊은 복사와 얕은 복사는 뭘까?

String, Number, Boolean에서의 복사

먼저 예제부터 살펴보자

let x = '마카롱'
let y = x
y = '바게트'
console.log(x,y)

다음과 같은 식에서 y에 x를 대입해서 y는 마카롱이 되었지만 y에 또다시 바게트라는 값을 대입했기 때문에 콘솔을 찍어보면 마카롱,바게트 라는 결과가 나오게 된다.

y의 값은 변해도 x의 값엔 영향을 주지 않는다

image.png

변수는 모두 메모리의 어딘가에 저장이 되는데, 대입을 하면 그 변수의 이름은 저장된 메모리의 주소를 가리킨다. 객체 말고 string, boolean, number들은 딱 그 값을 복사하는데 객체 같은 경우는 좀 다르다. 배열 또한 객체기 때문에 예시를 배열로 들어보았다~

let arr = [1,2,3]
let plus = arr;
plus[0]=0;
console.log(arr);
console.log(plus);

위의 코드를 콘솔에 찍어보면 둘 다 [0,2,3]이 나온다. 메모리에 [1,2,3]이라는 값을 가진 애는 arr와 plus 둘. 값은 하나인데 변수가 여러개일 때 이것을 참조라고 한다.
마치 내 이름이 김두리지만 둘둘이라던지 킹둘이라던지 별명이 많은 것처럼 훗
동일한 값에 변수가 여러개기 때문에 변수가 바뀌면 원본도 바뀌게 된다!
이걸 방지하려면 메모리에 한 값당 한 변수씩! 할당을 해줘야한다.

복사

여기서 나오는게 바로 복사라는 개념이다.

  • 얕은 복사 : 상위객체만 새로 생성되고 내부 객체는 참조관계
  • 깊은 복사 : 내부객체까지 전부 다 새로 생성되는 것

예제

let profile = {
  name: "김개발",
  address: {
    home: "한강아파트",
    company: "위워크 선릉2호점"
  },
  hobby: "programming"
}

const addProperty = info => {
}

// 호출 예
let newProfile = addProperty({ age: 20 });
console.log('profile => ', profile);
console.log('newProfile =>', newProfile);

addProperty 라는 함수를 통해 newProfile에는 새로운 값이 추가되어야 하고, 원본 객체는 손상시키면 안된다.

내가 접근한 방법

const addProperty = info => {
  const sth_new = {}
  for(let i in profile) {
    sth_new[i] = profile[i]
  }
  return Object.assign(sth_new, info)
}

먼저 sthnew라는 빈 객체를 만들고 for in 문을 돌려서 profile의 값들을 다 빈 객체에 옮겼고, 리턴 값으론 Object.assign을 이용해 인자를 들어가는 info와 sthnew를 merge시켜주었다.

근데 굳이 for in 문을 안 돌려도 됐던 것..!!

const addProperty = info => {
  const copyProperty = Object.assign({}, profile);
  return Object.assign(copyProperty, info)
}

그냥 새 객체를 Object.assign()을 이용해 선언해주고 리턴에 그걸 한번 더 써서 info를 넣어주면 됐다 헐~~

더 간단하게는

const addProperty = info => {
  return {
    ...info,
    ...profile
  }
}

세상에… 전개연산자로 한큐에 끝낼수 있다 전개연산자를 한정적으로만 써서 이런 기능이 있을줄 몰랐다

MDN 전개연산자에서 딱 처음 두개, apply 대신이랑 new와 함께 쓰는 것만 해봤는데 복사에 이렇게 유용하게 쓰이다닛..! 자주 활용해봐야겠다.

더 고난이도 방법으론 재귀를 쓰는 방법이 있다.

const addProperty = info => {
 let newProfile = {};
 // recursion
 function copyObject(data, newData){
   let typeOfInputData = typeof(data);
   if(typeOfInputData != 'object'){
       return data;
   }
   else{
     for(let key in data){
         let typeOfData = typeof(data[key]);
         if(typeOfData === 'object'){
          if(Array.isArray(data[key])){
               newData[key] = [];
           }
           else{
               newData[key] = {};
           }
           copyObject(data[key], newData[key]);
         }
         else{
           newData[key] = data[key];
         }
     }
   }
   return newData;
 }
 // 원본 복사
 copyObject(profile, newProfile);
 // 객체 추가
 copyObject(info, newProfile);
 return newProfile;
}

우리 기수 동기인 광훈님의 방법.. 와… 정말 어나더 클래스 대단쓰 이걸 재귀로 생각할 수 있었다니 와… 그저 감탄만 나온다

하나의 주제에 대해 서로 다양한 방법으로 생각해볼 수 있는 좋은 시간이었다! 다음 주제는 무엇이 될지 궁금하군 룰루~♬

Reference

  • wecode repl.it
  • MDN