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.