Come unire due oggetti javascript insieme in ES6 +?


141

Sono stanco di dover sempre scrivere codice in questo modo:

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

O se non voglio scrivere il codice da solo, implementare una libreria che lo fa già. Sicuramente ES6 + sta venendo in soccorso su questo ci fornirà qualcosa come un Object.prototype.extend(obj2...)oObject.extend(obj1,obj2...)

Quindi ES6 + fornisce tale funzionalità? Se non già presente, è prevista tale funzionalità? Se non pianificato, allora perché no?


3
Quindi perché non l'hai aggiunto alla tua libreria?
RobG,

12
@RobG questa domanda riguarda la speranza che l'ES6 ci rimuova dal dover prima necessitare di tali schifezze da scaldabagno.Per quello che vale: github.com/balupton/bal-util/blob/…
balupton

Non credo che esista un modo generale per copiare le coppie nome / valore da un oggetto a un altro. Ti occupi solo delle proprietà proprie o di quelle della [[Prototype]]catena? Fai copie "profonde" o "poco profonde"? Che dire delle proprietà non enumerabili e non scrivibili? Penso che preferirei avere una piccola funzione di libreria che fa ciò di cui ho bisogno, e soprattutto è comunque evitabile.
RobG,

Risposte:


206

Sarai in grado di eseguire una fusione / estensione / assegnazione superficiali in ES6 utilizzando Object.assign:

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

Sintassi:

Object.assign ( target , fonti );

dove ... fonti rappresenta gli oggetti di origine.

Esempio:

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

Object.assign(obj1, obj2);

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

64
Una piccola nota: Object.assign muta il bersaglio. Se non è quello che vuoi, puoi chiamarlo con un oggetto vuoto:let merged = Object.assign({}, source1, source2);
David

20
Si noti che questa è un'estensione poco profonda ... Gli oggetti nidificati NON vengono uniti
monzonj

@monzonj, non esiste alcuna opzione per estendere oggetti nidificati, senza usare lodash o mout?
Joao Falcao,

1
C'è un buon modo per unire oggetti profondamente annidati senza una libreria usando solo Object.assign: vedi la mia risposta qui
Ruslan,

Sta usando un vecchio modo per estendere gli oggetti nidificatiJSON.parse(JSON.stringify(src))
Andre Figueiredo,

162

È possibile utilizzare la sintassi di diffusione dell'oggetto per questo:

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

Per gli array l'operatore spread era già parte di ES6 (ES2015), ma per gli oggetti è stato aggiunto alle specifiche del linguaggio in ES9 (ES2018). La sua proposta è stata abilitata di default in strumenti come Babel molto prima.


3
No ufficialmente si chiama ES2015 ora: P Da quando la destrutturazione non fa parte di ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Esecuzione di babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Output:{ foo: 123, bar: 234 }
Thijs Koerselman

9
Non è destrutturante, si sta diffondendo - e no, per gli oggetti non fa parte di ES6. Dovresti disabilitare le bozze sperimentali ES7 nella tua babele.
Bergi,

2
Ah perdonami. Hai ragione. Al momento è una funzionalità Babel Stage 2. github.com/sebmarkbage/ecmascript-rest-spread Non me ne sono mai reso conto perché l'ho usato dall'inizio con Babel ed è abilitato di default. Ma dal momento che devi traspilare comunque, e la diffusione dell'oggetto è una cosa piuttosto semplice, lo consiglierei comunque. Lo adoro.
Thijs Koerselman,

Sono abilitati per impostazione predefinita, davvero? Sembra un bug.
Bergi,

2
"Le proposte di livello 2 o superiore sono abilitate per impostazione predefinita". babeljs.io/docs/usage/experimental
Thijs Koerselman

14

So che questo è un po 'un vecchio problema, ma la soluzione più semplice in ES2015 / ES6 è in realtà abbastanza semplice, usando Object.assign (),

Speriamo che questo aiuti, anche questa fusione 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;
}

Esempio di utilizzo:

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

L'aggiunta di Object.mixinè attualmente in discussione per prendersi cura del comportamento richiesto. https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Anche se non è ancora nella bozza di ES6, sembra che ci sia molto supporto per questo, quindi penso che presto apparirà nelle bozze.



5
Attenzione : questa risposta non è più corretta, vedi la risposta di Jack per un approccio corretto e funzionante.
Benjamin Gruenbaum,

Object.mixin è stato sostituito da Object.assign
gotofritz il

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 o Babele

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

1
@FilipBartuzi che non è ES6 a cui sei collegato. Ma sostanzialmente sta facendo l'equivalente di _.extend () in lodash / underscore.
Nostalg.io,

5

Forse il Object.definePropertiesmetodo ES5 farà il lavoro?

per esempio

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

Object.defineProperties(a, b);

alert(a.age); // 37

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


Stai attento, però. Su almeno un browser ciò ha implicazioni sulle prestazioni.
Reuben Morais,

1
Penso che la parte più interessante sia quella che definePropertiesdefinisce le proprie proprietà. Non sovrascrive le proprietà sulla [[prototype]]catena, le ombreggia.
RobG,

2
Un buon suggerimento, anche se in realtà non è un ampliamento in quanto è più per definire come le proprietà dovrebbero comportarsi ... Fare un semplice Object.defineProperties (obj1, obj2) causerebbe risultati inaspettati.
Balupton,

dovrebbe usare Object.getOwnPropertyDescriptoranche per impostare la proprietà quando è un valore complesso, o copierete per riferimento.
dmp,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.