Wie füge ich zwei Javascript-Objekte in ES6 + zusammen?


141

Ich habe es satt, immer so Code schreiben zu müssen:

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

Oder wenn ich den Code nicht selbst schreiben möchte, implementieren Sie eine Bibliothek, die dies bereits tut. Sicherlich kommt ES6 + zur Rettung, um uns so etwas wie ein Object.prototype.extend(obj2...)oder zu liefernObject.extend(obj1,obj2...)

Bietet ES6 + solche Funktionen? Wenn nicht bereits vorhanden, ist eine solche Funktionalität dann geplant? Wenn nicht geplant, warum dann nicht?


3
Warum haben Sie es nicht zu Ihrer Bibliothek hinzugefügt ?
RobG

12
@RobG Diese Frage handelt von der Hoffnung, dass ES6 uns davon abhält, überhaupt einen solchen Boilerplate-Mist zu brauchen. Für das, was es wert ist: github.com/balupton/bal-util/blob/…
balupton

Ich glaube nicht, dass es eine allgemeine Möglichkeit gibt, die Name / Wert-Paare von einem Objekt auf ein anderes zu kopieren. Beschäftigen Sie sich nur mit eigenen Eigenschaften oder denen in der [[Prototype]]Kette? Machst du "tiefe" oder "flache" Kopien? Was ist mit nicht aufzählbaren und nicht beschreibbaren Eigenschaften? Ich denke, ich hätte lieber eine kleine Bibliotheksfunktion, die das tut, was ich brauche, und meistens ist sie sowieso vermeidbar.
RobG

Antworten:


206

Mit Object.assign können Sie in ES6 eine flache Zusammenführung / Erweiterung / Zuweisung durchführen:

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

Syntax:

Object.assign ( Ziel , Quellen );

Dabei steht ... source für das / die Quellobjekt (e).

Beispiel:

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

Object.assign(obj1, obj2);

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

64
Ein kleiner Hinweis: Object.assign mutiert das Ziel. Wenn Sie das nicht möchten, können Sie es mit einem leeren Objekt aufrufen:let merged = Object.assign({}, source1, source2);
David

20
Bitte beachten Sie, dass dies eine flache Ausdehnung ist ... verschachtelte Objekte werden NICHT zusammengeführt
monzonj

@monzonj, gibt es keine Möglichkeit, verschachtelte Objekte zu erweitern, ohne lodash oder mout zu verwenden?
Joao Falcao

1
Es gibt die gute Möglichkeit, tief verschachtelte Objekte ohne Bibliothek zusammenzuführen, indem Sie einfach Object.assign: siehe meine Antwort hier
Ruslan

Eine alte Methode, um verschachtelte Objekte zu erweitern, ist die Verwendung vonJSON.parse(JSON.stringify(src))
Andre Figueiredo

162

Sie können hierfür die Objektverbreitungssyntax verwenden :

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

Für Arrays war der Spread-Operator bereits Teil von ES6 (ES2015), für Objekte wurde er jedoch der Sprachspezifikation bei ES9 (ES2018) hinzugefügt. Sein Vorschlag wurde in Tools wie Babel schon lange vorher standardmäßig aktiviert.


3
Nein, offiziell heißt es jetzt ES2015: P Seit wann ist Destrukturierung nicht Teil von ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Ausführen von babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Ausgabe:{ foo: 123, bar: 234 }
Thijs Koerselman

9
Das ist keine Destrukturierung, es breitet sich aus - und nein, für Objekte ist es nicht Teil von ES6. Sie sollten experimentelle ES7-Entwürfe in Ihrem Babel deaktivieren.
Bergi

2
Ah vergib mir. Du hast recht. Es ist im Moment ein Babel Stage 2 Feature. github.com/sebmarkbage/ecmascript-rest-spread Ich habe das nie bemerkt, weil ich es von Anfang an mit babel verwendet habe und es standardmäßig aktiviert ist. Aber da Sie sowieso transpilieren müssen und die Objektverteilung eine ziemlich einfache Sache ist, würde ich es trotzdem empfehlen. Ich liebe es.
Thijs Koerselman

Sie sind standardmäßig aktiviert, wirklich? Das klingt nach einem Fehler.
Bergi

2
"Vorschläge der Stufe 2 oder höher sind standardmäßig aktiviert". babeljs.io/docs/usage/experimental
Thijs Koerselman

13

Ich weiß, dass dies ein altes Problem ist, aber die einfachste Lösung in ES2015 / ES6 ist mit Object.assign () recht einfach.

Hoffentlich hilft das, dies führt auch zum Zusammenführen von 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;
}

Anwendungsbeispiel:

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

Die Hinzufügung von Object.mixinwird derzeit diskutiert, um das von Ihnen gewünschte Verhalten zu berücksichtigen.https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Obwohl es noch nicht im ES6-Entwurf enthalten ist, scheint es viel Unterstützung dafür zu geben, daher denke ich, dass es bald in den Entwürfen auftauchen wird.


13
.mixinwurde von TC39 fallen gelassen.
Knu

5
Warnung - Diese Antwort ist nicht mehr korrekt. In der Antwort von Jack finden Sie einen korrekten und funktionierenden Ansatz.
Benjamin Gruenbaum

Object.mixin wurde durch 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 oder Babel

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

1
@FilipBartuzi das ist nicht ES6, mit dem Sie verlinkt haben. Aber es macht im Grunde das Äquivalent zu _.extend () in lodash / underscore.
Nostalg.io

5

Vielleicht erledigt die ES5- Object.definePropertiesMethode den Job?

z.B

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

Object.defineProperties(a, b);

alert(a.age); // 37

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


Sei aber vorsichtig. In mindestens einem Browser hat dies Auswirkungen auf die Leistung.
Reuben Morais

1
Ich denke, der interessanteste Teil ist, dass definePropertieseigene Eigenschaften definiert werden. Es überschreibt keine Eigenschaften in der [[prototype]]Kette, es schattiert sie.
RobG

2
Guter Vorschlag, aber nicht wirklich eine Erweiterung, da er eher dazu dient, das Verhalten von Eigenschaften zu definieren ... Ein einfaches Object.defineProperties (obj1, obj2) würde zu unerwarteten Ergebnissen führen.
Balupton

müsste Object.getOwnPropertyDescriptorauch verwendet werden, um die Eigenschaft festzulegen, wenn es sich um einen komplexen Wert handelt, oder Sie kopieren als Referenz.
dmp
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.