객체를 병합하는 Object.assign, Spread Syntax

캡틴 노드랭크·2021년 2월 23일
0

자바스크립트

목록 보기
2/2

assign을 다시 알아보는 이유는 redux를 배웠을 때, reducer를 구현하는 코드에서 switch문을 써서 case로 타입마다 분기를 나눌때 보통 아래의 코드 처럼 쓰인다.

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return { 
        ...state, 
        visibilityFilter: action.filter 
      }
    default:
      return state
  }
}

case문 안의 return을 보게되면 spread 연산자를 써서 새로운 상태를 반환하는 코드인데, 저렇게 표현하는 코드를 봤을 때 제대로 이해하지도 못했고, 자세히 어떤 역할을 하는지 너무 궁금했다. 찾아보다가 결국 Object.assign()spread 연산자로 표현한거라는 것을 알게 되었다.

예시

    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })

다시 복습할겸 Object.assign()을 알아보자.

Object.assign()

MDN에서는 열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용합니다. 대상 객체를 반환합니다. 라고 작성되있다.

쉽게 말하면 어떤 객체가 담긴 메모리의 주소를 참조하여 복사한 뒤에 객체를 병합한다. (얕은 복사의 대표적인 메소드)

Object.assign(target, ...sources)

target: 담아줄 대상
sources: 하나 이상의 객체

대충 이렇게 쓰인다.

const person = {
 name:"아무개",
 age: 20,
}

const assign = Object.assign({}, person)
assign //{ name:"아무개", age: 20, }
  1. 먼저 여러 속성이 담긴 객체를 생성해 person이라는 변수에 담아주었다.

  2. assign메소드의 첫번째 인자 targetperson의 메모리 주소를 참조하여 복붙한다.

  3. 마지막으로 target이 새 메모리 주소에 담겨 반환한다.

여러개의 객체 병합하기

const game = { AOS: "League of Legend" };
const game2 = { Sim: "DCS Worlds" };
const game3 = { VR: "Half-Life: Alyx" };

const myGames = Object.assign(game, game2, game3);
myGames // {AOS: "League of Legend", Sim: "DCS Worlds", VR: "Half-Life: Alyx"}

어떠한 객체를 병합할 때 동일한 키를 가진 속성이 있는 경우..

const lang = { Aphabet: "abc" };
const lang2 = { Aphabet: "abc, ...z" };
const lang3 = { Hangul: "가나다" };

const languages = Object.assign(lang, lang2, lang3);
languages //{Aphabet: "abc, ...z", Hangul: "가나다"}

이렇게 덮어씌어진다.

중첩된 객체 복사

위에서는 단순히 객체가 중첩되지 않았을 경우지만 만약 중첩된다면 어떻게 될까?

const company = { 
   name: 'AMD',
   ceo: 'Lisa Su',
   product: {
     CPU: "Ryzen, EPYC, Thread-Ripper...",
     GPU: "Radeon",
   },
 };

중첩된 객체를 사용할 경우 다음과 같은 문제를 가진다.
우선 Object.assign()을 사용하여 clone에 담아주자.

const clone = Object.assign({}, company)

company.product에서 clone.product로 복사하게 되면 company와 clone은 같은 product를 공유하게 된다. .product또한 객체이기 때문에 같은 주소 값이 복사 되기 때문이다.

콘솔로 자세히 알아보자.

clone.name = "IBM"
console.log(clone.name) // "IBM"
console.log(company.name) // "AMD"

clone.name의 값을 변경해줘도 다른 메모리 주소에 담겨있기 때문에 company.name은 변하지 않는다.

clone.product.CPU = "PowerPC"
console.log(clone.product.CPU) // "PowerPC"
console.log(company.product.CPU) // "PowerPC"

이렇게 원본, 클론 모두 값이 변하게 된다. 이것을 깊은 복사(Deep Cloning)를 하기 위해선 다음과 같이 쓰인다.(for MDN)

  let obj1 = { a: 0 , b: { c: 0}};
  let obj3 = JSON.parse(JSON.stringify(obj1));
  obj1.a = 4;
  obj1.b.c = 4;
  console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
}

뭐 대충 이쯤이면 된 것 같으니 Object.assign의 전개연산자로 사용하는 방법을 알아보자..

Spread 연산자

const game = { AOS: "League of Legend" };
const game2 = { Sim: "DCS Worlds" };
const game3 = { VR: "Half-Life: Alyx" };

const myGames = Object.assign(game, game2, game3);
myGames // {AOS: "League of Legend", Sim: "DCS Worlds", VR: "Half-Life: Alyx"}

위의 코드를 이렇게 Spread 연산자를 써서 더 간단하게 만들 수 있다.

const myGames = {
 ...game,
 ...game2,
 ...game3,
}     
myGames // {AOS: "League of Legend", Sim: "DCS Worlds", VR: "Half-Life: Alyx"}

도대체 이게 뭔가 싶고, 너무 충격적이다.
또 속성을 추가하거나 바꿔줄 수 있다.

const games = {
 ...game,
 AOS: "Heros of the Storm", TPS: "Grand Theft Auto 5"
}    

이렇게 redux에서 매번 상태를 바꿀때 reducer에 왜 이런 코드가 들어가는지 알게되었다...

출처 - https://ko.javascript.info/object-copy
출처2 - https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

profile
다시 처음부터 천천히... 급할필요가 없다.

0개의 댓글