ES6 +에서 두 개의 자바 스크립트 객체를 어떻게 병합합니까?


141

나는 항상 다음과 같은 코드를 작성해야한다는 것에 지쳤다.

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

또는 코드를 직접 작성하지 않으려면 이미 코드를 작성하는 라이브러리를 구현하십시오. 확실히 ES6 +이의 구조에 오는 것은 같은 우리에게 제공 Object.prototype.extend(obj2...)또는Object.extend(obj1,obj2...)

ES6 +는 그러한 기능을 제공합니까? 아직없는 경우 그러한 기능이 계획되어 있습니까? 계획되지 않았다면 왜 안됩니까?


3
그럼 왜에 추가하지 않은 사용자의 라이브러리?
RobG

12
이 질문에 @RobG 것은 ES6 처음 place.For 이러한 보일러 쓰레기를 필요로하는 데에서 우리를 제거 할 것이라는 희망에 대해 무엇 그것의 가치 : github.com/balupton/bal-util/blob/...
balupton

한 객체에서 다른 객체로 이름 / 값 쌍을 복사하는 일반적인 방법은 없다고 생각합니다. 당신은 자신의 속성이나 [[Prototype]]체인 의 속성 만 처리 합니까? "깊은"또는 "얕은"사본을 사용합니까? 열거 할 수없고 쓸 수없는 속성은 어떻습니까? 필자는 필요한 것을 수행하는 작은 라이브러리 함수를 원한다고 생각하며 대부분 어쨌든 피할 수 있습니다.
RobG

답변:


206

Object.assign을 사용하여 ES6에서 얕은 병합 / 확장 / 할당을 수행 할 수 있습니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

통사론:

Object.assign ( target , sources );

여기서 ... sources 는 소스 객체를 나타냅니다.

예:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
작은 메모 : Object.assign은 대상을 변경합니다. 그것이 원하는 것이 아니라면 빈 객체로 호출 할 수 있습니다.let merged = Object.assign({}, source1, source2);
david

20
이것은 얕은 확장입니다 ... 중첩 된 객체는 병합되지 않습니다
monzonj

@ monzonj, lodash 또는 mout을 사용하지 않고 중첩 된 객체를 확장하는 옵션이 없습니까?
주앙 팔 카오

1
라이브러리를 사용하지 않고 깊게 중첩 된 객체를 병합하는 좋은 방법이 있습니다 Object.assign: 여기 내 대답보기
Ruslan

중첩 된 객체를 확장하는 오래된 방법은 다음과 같습니다.JSON.parse(JSON.stringify(src))
Andre Figueiredo

162

이를 위해 오브젝트 스프레드 구문 을 사용할 수 있습니다 .

const merged = {...obj1, ...obj2}

배열의 경우 스프레드 연산자는 이미 ES6 (ES2015)의 일부이지만 객체의 경우 ES9 (ES2018)의 언어 사양에 추가되었습니다. Babel과 같은 도구에서 기본적으로 활성화 된 제안은 그 이전입니다.


3
공식적으로 현재 ES2015라고하지 않습니다 : P ES6의 일부가 아닌 구조화는 언제부터? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... 실행 바벨 - 노드 : const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) 출력 :{ foo: 123, bar: 234 }
티스 Koerselman

9
그것은 파괴적이지 않고 확산되고 있습니다-그리고 객체의 경우 ES6의 일부가 아닙니다. babel에서 실험적인 ES7 초안을 비활성화해야합니다.
Bergi

2
아 용서 해줘 네 말이 맞아 현재 바젤 2 단계 기능입니다. github.com/sebmarkbage/ecmascript-rest-spread 내가 babel을 처음부터 사용했기 때문에 기본적으로 활성화되어 있다는 것을 결코 깨닫지 못했습니다. 그러나 어쨌든 번역해야하고 객체 확산은 매우 간단하므로 어쨌든 권장합니다. 나는 그것을 좋아한다.
Thijs Koerselman

그들은 기본적으로 활성화되어 있습니까? 그것은 버그처럼 들립니다.
Bergi

2
"2 단계 이상인 제안은 기본적으로 활성화되어 있습니다." babeljs.io/docs/usage/experimental
Thijs Koerselman

14

나는 이것이 오래된 문제라는 것을 알고 있지만 ES2015 / ES6에서 가장 쉬운 해결책은 실제로 Object.assign (),

잘하면 이것이 도움이 될 것입니다 .DEEP 병합도 수행합니다.

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

사용법 예 :

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

7

추가 Object.mixin는 현재 요청하는 동작을 처리하기 위해 논의 중입니다.https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

아직 ES6 초안에는 없지만 많은 지원이 필요한 것 같으므로 곧 초안에 나타날 것입니다.


13
.mixinTC39에 의해 삭제 되었습니다.
Knu

5
경고 -이 답변은 더 이상 정확하지 않습니다. 정확하고 효과적인 방법은 Jack의 답변을 참조하십시오.
Benjamin Gruenbaum

Object.mixin은 Object.assign로 대체되었습니다
gotofritz

7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 또는 바벨

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi 귀하가 연결 한 ES6이 아닙니다. 그러나 기본적으로 lodash / underscore에서 _.extend ()와 동일합니다.
Nostalg.io

5

아마도 ES5 Object.defineProperties방법이 작동합니까?

예 :

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

MDN 설명서 : https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


그래도 조심하십시오. 에 적어도 하나의 브라우저 이 성능에 영향이 있습니다.
Reuben Morais

1
가장 흥미로운 부분은 defineProperties자신의 속성 을 정의하는 것입니다. [[prototype]]체인의 속성을 덮어 쓰지 않고 그림자로 만듭니다.
RobG December

2
좋은 제안이지만 실제로는 속성이 어떻게 동작해야 하는지를 정의하기 위해 확장 할 필요는 없습니다. 간단한 Object.defineProperties (obj1, obj2)를 수행하면 예기치 않은 결과가 발생합니다.
balupton

Object.getOwnPropertyDescriptor속성이 복잡한 값일 때 속성을 설정하는 데 사용해야 합니다. 그렇지 않으면 참조로 복사합니다.
dmp
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.