joyful
TIP 11: Object.assign()으로 조작 없이 객체를 생성하라 본문
Object.assign()을 이용해 조작하지 않고 객체를 업데이트하는 방법을 알아보겠다.
객체는 많은 이점을 갖고 있지만, 배열과 마찬가지로 조작의 위험성이 있으므로 주의해야 한다.
배열과 마찬가지로 원래의 데이터를 유지하는 새로운 객체를 생성하는 법을 알아보자.
문제 1
const defaults = {
author: '',
title: '',
year: 2017,
rating: null,
};
const book = {
author: 'Joe Morgan',
title: 'Simplifying JavaScript',
};
function addBookDefaults(book, defaults) {
const fields = Object.keys(defaults); //['author', 'title', 'year', 'rating']
const updated = {};
for (let i = 0; i < fields.length; i++) {
const field = fields[i];
updated[field] = book[field] || defaults[field];
}
return updated;
}
위의 예제코드는 딱히 잘못된 부분은 없지만 장황하다.
이때 Object.assign()을 사용하면 다른 객체의 속성을 이용해서 객체를 업데이트 할 수 있다.
Object.assign()의 작동 방법은 다음과 같다.
- 해당 메서드로 일련의 객체를 전달 받는다.
- 가장 먼저 인수로 받은 객체를 뒤이어 인수로 넘긴 객체의 키-값을 이용해서 업데이트한다.
- 업데이트된 첫 번째 객체를 반환한다. (먼저 전달한 객체부터 적용)
const book = {
author: 'Joe Morgan',
title: 'Simplifying JavaScript',
};
const defaults = {
author: '',
title: '',
year: 2017,
rating: null,
};
Object.assign(defaults, book);
// {
// author: 'Joe Morgan',
// title: 'Simplifying JavaScript',
// year: 2017,
// rating: null,
// }
Object.assign()으로 아홉 줄이었던 addBookDefaults 함수를 한 줄로 바꾸었다.
하지만 이때 기본값 객체를 갱신하면서 원본 객체를 조작하게 된다.
const anotherBook = {
title: 'Another book',
year: 2016,
};
Object.assign(defaults, anotherBook);
// {
// author: 'Joe Morgan',
// title: 'Another book',
// year: 2016,
// rating: null,
// }
책 정보를 담은 다른 객체를 이용해서 한 번 더 실행해보면
기존 책의 author(Joe Morgan)가 anotherBook의 author로 저장된다.
Joe Morgan이 쓰지도 않은 책의 저자가 된 것이다.
문제 2
우선 위의 코드에서는 첫 번째 객체에 빈 객체를 사용하여 해결할 수 있다.
그렇게 되면 빈 객체에 새로운 값이 업데이트되어 반환되고,
다른 객체에는 조작이 발생하지 않는다.
const defaults = {
author: '',
title: '',
year: 2017,
rating: null,
};
const book = {
author: 'Joe Morgan',
title: 'Simplifying JavaScript',
};
const updated = Object.assign({}, defaults, book);
하지만 이렇게 되면 값만 복사되는 문제가 생긴다.
const defaultEmployee = {
name: {
first: '',
last: '',
},
years: 0,
};
const employee = Object.assign({}, defaultEmployee);
위의 코드와 같이 중첩객체를 복사하는 것을 깊은 복사(deep copy) 또는 깊은 병합(deep merge)라고 한다.
해당 코드에서는 years 속성을 복사할 수 있지만, name 속성은 복사할 수 없다.
중첩 객체는 해당 객체를 담고 있는 객체와 독립적으로 존재하기 때문이다.
중첩된 객체를 담고 있는 객체가 가지고 있는 것은 중첩된 객체에 대한 참조뿐이고,
참조를 복사하는 것은 그 위치를 복사하는 것에 불과하다.
따라서 원본 객체 또는 복사한 객체 중 어디서라도 중첩된 객체의 값을 변경하면 원본 객체와 복사한 객체 모두 변경된다.
중첩된 객체로 인한 문제의 해결법은 두 가지가 있다.
해결 1
중첩된 객체를 두지 않음으로서 해결한다.
(객체를 중첩하지 않아도 괜찮은 경우에 가능)
employee.name.first = 'Joe';
defaultEmployee;
// {
// name: {
// first:'Joe',
// last: '',
// },
// years: 0
// }
해결 2
Object.assign()을 이용해서 중첩된 객체를 복사하여 해결한다.
const employee2 = Object.assign(
{},
defaultEmployee,
{
name: Object.assign({}, defaultEmployee.name),
},
);
'자바스크립트 코딩의 기술' 카테고리의 다른 글
TIP 13: 맵으로 명확하게 키-값 데이터를 갱신하라 (1) | 2023.11.17 |
---|---|
TIP 12: 객체 펼침 연산자로 정보를 갱신하라 (2) | 2023.11.11 |
TIP 10: 객체를 이용해 정적인 키-값을 탐색하라 (2) | 2023.11.07 |
TIP 9: 펼침 연산자로 정렬에 의한 혼란을 피하라 (2) | 2023.11.04 |
TIP 8: push() 메서드 대신 펼침 연산자로 원본 변경을 피하라 (0) | 2023.11.04 |