Come concatenare proprietà da più oggetti JavaScript


105

Sto cercando il modo migliore per "aggiungere" più oggetti JavaScript (array associativi).

Ad esempio, dato:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

qual è il modo migliore per calcolare:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

3
Una nota semantica: nonostante la sintassi [], non sono affatto array. L'ordine non è realmente garantito.
Álvaro González

1
L'ordine di iterazione non è garantito per gli standard ecma. Ma è il modo in cui è implementato nella maggior parte dei browser. (Da John Resig) Questo comportamento è esplicitamente lasciato indefinito dalla specifica ECMAScript. In ECMA-262, sezione 12.6.4: La meccanica dell'enumerazione delle proprietà ... dipende dall'implementazione. Tuttavia, la specifica è abbastanza diversa dall'implementazione. Tutte le implementazioni moderne di ECMAScript eseguono l'iterazione delle proprietà degli oggetti nell'ordine in cui sono state definite. Per questo motivo il team di Chrome ha ritenuto che si tratti di un bug e lo risolverà.
Juan Mendes

Risposte:


159

ECMAscript 6 introdotto Object.assign()per ottenere questo risultato in modo nativo in Javascript.

Il metodo Object.assign () viene utilizzato per copiare i valori di tutte le proprietà enumerabili da uno o più oggetti di origine a un oggetto di destinazione. Restituirà l'oggetto di destinazione.

Documentazione MDN su Object.assign ()

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assignè supportato in molti browser moderni ma non ancora in tutti. Usa un transpiler come Babel e Traceur per generare JavaScript ES5 compatibile con le versioni precedenti.


4
Questo è uno dei migliori che potrei dire. Poiché E6 è ora principalmente utilizzato, Object.assign è la risposta migliore.
Vimalraj Selvam

6
Se non sai quanti oggetti devono essere uniti, bevause sono in un array puoi unirli come segue:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri

1
Un'alternativa all'uso Object.assign.applyper unire un array di oggetti, è invece usare l'operatore spread:Object.assign( ...objects )
Spen

@Spen che è già inclusa come risposta a questa domanda. Non ho visto alcun vantaggio nel duplicarlo qui.
filoxo

dopo 4 ore, questa risposta ha risolto il mio problema in Angular 7. Grazie per la semplicità e l'accuratezza della risposta.
Gel

35

Potresti usare jquery in $.extendquesto modo:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


+1 Anche se non usi il metodo di jQuery, potresti usare il loro codice per aiutare a costruire la tua (forse, più specifica) implementazione.
tvanfosson

25
@Randal: ci sono molte ottime ragioni per non usare jQuery.
Tim Down

3
Modifica:d = $.extend({},a,b,c);
Bob Stein

34

Questo dovrebbe farlo:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Produzione:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

Non lengthcerca la dimensione dell'array a ogni chiamata? Sono così abituato a scrivere for (var i = 0, len = array.length; i < len; ++i)che non riesco a ricordare a mente perché ho iniziato a farlo.
tvanfosson

1
Sì, è corretto. È una prestazione migliore memorizzare nella cache la lunghezza una volta. Tuttavia, poiché è probabile che la dimensione degli argomenti "array" non sia mai molto grande, in questo caso non avrà molta importanza.
jhurshman

1
No, tranne leggermente su IE6. L'accesso alla proprietà di lunghezza costa come l'accesso alla variabile len.
Alsciende

1
@Juan, credo che tu abbia torto e ho fatto alcuni test per prendere una decisione. La memorizzazione nella cache della lunghezza è un semplice mito di ottimizzazione obsoleto da molti anni e rende il codice (leggermente) meno leggibile. In realtà, memorizzare la lunghezza nella cache a volte rallenta il browser (Safari).
Alsciende

2
Non sarebbe meglio scrivere "for (var p in ..." invece di "for (p in ..."?
Hugo

24

ECMAScript 6 ha una sintassi diffusa . E ora puoi farlo:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}


12

Il carattere di sottolineatura ha pochi metodi per farlo;

1. _.extend (destinazione, * sorgenti)

Copiare tutte le proprietà negli oggetti di origine nell'oggetto di destinazione e restituire l' oggetto di destinazione .

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

O

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults (oggetto, * predefiniti)

Compila le proprietà non definite nell'oggetto con i valori degli oggetti predefiniti e restituisci l' oggetto .

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

O

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

4

Perché la funzione dovrebbe essere limitata a 3 argomenti? Inoltre, controlla hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

4

La clonazione superficiale (escluso il prototipo) o l'unione di oggetti è ora possibile utilizzando una sintassi più breve di Object.assign () .

La sintassi di diffusione per i letterali oggetto è stata introdotta in ECMAScript 2018 ):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

L'operatore Spread (...) è supportato in molti browser moderni ma non in tutti.

Quindi, si consiglia di utilizzare un transpiler come Babel per convertire il codice ECMAScript 2015+ in una versione retrocompatibile di JavaScript nei browser o negli ambienti attuali e precedenti.

Questo è il codice equivalente che Babel genererà per te:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Questa è una risposta molto più robusta rispetto alla risposta accettata. Grazie!
Kaleb Anderson

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Avviso: le proprietà esistenti negli oggetti precedenti verranno sovrascritte.


2
Questo ha l'effetto collaterale che a === dalla fine. Potrebbe essere ok e potrebbe non esserlo.
tvanfosson

2

È facile usare ES7 spread operator per un oggetto, nella tua console del browser put

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

1
Bello. Questa domanda ha più di 10 anni, lieto che un'operazione così semplice sia facile ora. Prima non era così facile se guardi le risposte degli altri.
Vlad

ecco perché ho lasciato la mia risposta :)
Purkhalo Alex

2

Per unire un numero dinamico di oggetti, possiamo usare Object.assigncon la sintassi diffusa .

const mergeObjs = (...objs) => Object.assign({}, ...objs);

La funzione precedente accetta un numero qualsiasi di oggetti, unendo tutte le loro proprietà in un nuovo oggetto con le proprietà degli oggetti successivi sovrascrivendo quelle degli oggetti precedenti.

demo:

Per unire una matrice di oggetti, può essere applicato un metodo simile.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

demo:


1

Probabilmente, il modo più veloce, efficiente e più generico è questo (puoi unire un numero qualsiasi di oggetti e persino copiare nel primo -> assegna):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

Consente inoltre di modificare il primo oggetto così come è passato per riferimento. Se non vuoi questo ma vuoi avere un oggetto completamente nuovo contenente tutte le proprietà, puoi passare {} come primo argomento.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

combinato_object e object1 contengono entrambi le proprietà di object1, object2, object3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

In questo caso, il combined_object contiene le proprietà di object1, object2, object3 ma object1 non viene modificato.

Controlla qui: https://jsfiddle.net/ppwovxey/1/

Nota: gli oggetti JavaScript vengono passati per riferimento.


1

ES6 ++

La domanda è l'aggiunta di vari oggetti diversi in uno.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

diciamo che hai un oggetto con più chiavi che sono oggetti:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

questa è stata la soluzione che ho trovato (devo ancora foreach: /)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

In questo modo possiamo aggiungere dinamicamente TUTTE le chiavi oggetto in una.

// Output => { bar: 'foo', foo: 'bar' }

0

Il più semplice: gli operatori di diffusione

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }

-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}
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.