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()을 알아보자.
MDN
에서는 열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용합니다. 대상 객체를 반환합니다.
라고 작성되있다.
쉽게 말하면 어떤 객체가 담긴 메모리의 주소를 참조하여 복사한 뒤에 객체를 병합한다. (얕은 복사의 대표적인 메소드)
Object.assign(target, ...sources)
target: 담아줄 대상
sources: 하나 이상의 객체
대충 이렇게 쓰인다.
const person = {
name:"아무개",
age: 20,
}
const assign = Object.assign({}, person)
assign //{ name:"아무개", age: 20, }
먼저 여러 속성이 담긴 객체를 생성해 person
이라는 변수에 담아주었다.
assign
메소드의 첫번째 인자 target
에 person
의 메모리 주소를 참조하여 복붙한다.
마지막으로 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의 전개연산자로 사용하는 방법을 알아보자..
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