기본
Object.assign()
메서드는 출처 객체들의 모든 열거 가능한 자체 속성을 복사해 대상 객체에 붙여 넣음.
그 후 대상 객체를 반환
Object.assign(target, ...sources)
예시
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
- 목표 객체의 속성 중 출처 객체와 동일한 키를 갖는 속성의 경우, 그 속성 값은 출처 객체의 속성 값으로 덮어 쓴다.
- 출처 객체들의 속성 중에서도 키가 겹칠 경우 뒤쪽 객체의 속성 값이 앞쪽 객체의 속성 값보다 우선 한다.
심화
객체 복제
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
깊은 복사 주의점
Object.assign()
은 속성의 값을 복사하기 때문에, 깊은 복사를 수행하려면 다른 방법을 사용해야 한다.
만약 출처 값이 객체에 대한 참조라면 참조 값만 복사
function test() {
'use strict';
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
// 깊은 복사
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}}
}
test();
객체 병합
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 목표 객체 자체가 변경됨.
같은 속성을 가진 객체 병합
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
심볼 속성 복사
const o1 = { a: 1 };
const o2 = { [Symbol('foo')]: 2 };
const obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
프로토타입 체인의 속성과 열거 불가능한 속성은 복사 불가
const obj = Object.create({ foo: 1 }, { // foo는 obj의 프로토타입 체인에 있음
bar: {
value: 2 // bar는 열거 불가능
},
baz: {
value: 3,
enumerable: true // baz는 열거 가능한 자체 속성
}
});
const copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }
원시 값은 객체로 래핑
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const v4 = Symbol('foo');
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 원시 값은 래핑하고, null과 undefined는 무시
// 참고: 문자열 래퍼만 자체 열거형 속성을 가질 수 있음
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
예외로 인한 복사 작업 중단
const target = Object.defineProperty({}, 'foo', {
value: 1,
writable: false
}); // target.foo는 읽기 전용 속성
Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" is read-only
// target.foo에 할당할 때 예외 발생
console.log(target.bar); // 2, 첫 번째 출처 객체는 성공적으로 복사함
console.log(target.foo2); // 3, 두 번째 출처 객체 중 첫 번째 속성도 성공적으로 복사함
console.log(target.foo); // 1, 여기에서 예외가 발생했음
console.log(target.foo3); // undefined, assign 메서드가 종료됨, foo3은 복사되지 않음
console.log(target.baz); // undefined, 세 번째 출처 객체도 복사되지 않음
접근자 복사
const obj = {
foo: 1,
get bar() {
return 2;
}
};
let copy = Object.assign({}, obj);
console.log(copy);
// { foo: 1, bar: 2 }, copy.bar의 값은 obj.bar의 접근자가 반환한 값
// 속성의 온전한 기술자를 복사해 할당하는 함수
function completeAssign(target, ...sources) {
sources.forEach(source => {
let descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
// 기본적으로 Object.assign은 열거 가능한 심볼도 복사함
Object.getOwnPropertySymbols(source).forEach(sym => {
let descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
}
copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }