Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

joyful

TIP 11: Object.assign()으로 조작 없이 객체를 생성하라 본문

자바스크립트 코딩의 기술

TIP 11: Object.assign()으로 조작 없이 객체를 생성하라

조이풀한 개발자 2023. 11. 11. 20:32

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()의 작동 방법은 다음과 같다.

 

  1. 해당 메서드로 일련의 객체를 전달 받는다.
  2. 가장 먼저 인수로 받은 객체를 뒤이어 인수로 넘긴 객체의 키-값을 이용해서 업데이트한다.
  3. 업데이트된 첫 번째 객체를 반환한다.  (먼저 전달한 객체부터 적용)
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),
  },
);