Unione di oggetti (array associativi)


147

Qual è il modo migliore / standard di unire due array associativi in ​​JavaScript? Ognuno lo fa semplicemente rotolando il proprio forloop?


10
non ci sono matrici associative in javascript btw, solo oggetti.
gblazex,

Crossref stessa domanda in Perl: stackoverflow.com/questions/350018/...
dreftymac

Risposte:


204

con jquery puoi chiamare $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(le matrici associate sono oggetti in js)

guarda qui: http://api.jquery.com/jQuery.extend/


modifica: Come ha suggerito Rymo, è meglio farlo in questo modo:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

Come qui obj1 (e obj2) rimangono invariati.


edit2: nel 2018 il modo per farlo è tramite Object.assign:

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

Se si lavora con ES6 questo può essere ottenuto con Spread Operator :

const obj3 = { ...obj1, ...obj2 };

54
o per evitare il muck obj1, usa un oggetto vuoto come bersaglio:$.extend({}, obj1, obj2)
Rymo

Sì, quando si tratta di chiusure e oggetti passati per riferimento, seguire i consigli di rymo per evitare di influenzare l'oggetto originale per le operazioni successive.
Nathan Smith,

2
Per i browser moderni, controlla la soluzione di @manfred utilizzando Object.assign(), che non si basa su JQuery se non stai già utilizzando la libreria.
Phil

Funziona, ma altera il primo parametro ed è qualcosa di cui devi essere consapevole. Vedi developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
kulpae

62

Ora nel 2016 direi che il modo migliore / standard è Object.assign ()
Pure Javascript. Non è necessario jQuery.

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

Maggiori informazioni, esempi e polyfill qui:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


Qual è il tipo di obj3? cosa succede se obj1 è di tipo IABC, obj3 manterrà quel tipo in seguito?
windmaomao

49

Ecco come funziona Prototype:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

chiamato come, ad esempio:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

EDIT : aggiunto hasOwnProperty () check come correttamente sottolineato da bucabay nei commenti


6
Avrai bisogno del test source.hasOwnProperty (proprietà) per assicurarti di copiare solo le proprietà immediate. Così com'è, questo potrebbe copiare tutte le proprietà comprese quelle derivate da Object.prototype
bucabay,

22

Keep it simple ...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

6
È necessario controllare hasOwnProperty per evitare di copiare qualsiasi proprietà suarrau1.prototype
LeeGee

@LeeGee ha ragione. Hai bisogno di quel hasOwnPropertycontrollo. Riferendosi agli oggetti come array è anche fuorviante (sono oggetti), i nomi arg dovrebbero comunicare che array2 è mutato o che dovrebbe essere restituito un nuovo oggetto. Modificherei la risposta ma in effetti diventerebbe quasi esattamente la risposta modificata di Jonathan Fingland che è già stata corretta.
Vaz,

14

Underscore ha anche un metodo di estensione:

Copia tutte le proprietà negli oggetti di origine sull'oggetto di destinazione. È in ordine, quindi l'ultima fonte sovrascriverà le proprietà con lo stesso nome negli argomenti precedenti.

_.extend(destination, *sources) 

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}


6

vuoi sovrascrivere una proprietà se i nomi sono uguali ma i valori non lo sono?

E vuoi cambiare permanentemente uno degli oggetti originali,

o vuoi che venga restituito un nuovo oggetto unito?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}

6

Rolling Your Extend / Mixin Function

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

Questo semplicemente estende uno splat di oggetti, in modo ricorsivo. Inoltre, nota che questa funzione ricorsiva è TCO ( Tail-Call Optimized ) poiché il suo ritorno è l'ultima chiamata a se stessa.

Inoltre, potresti volere proprietà mirate . In questo caso, si consiglia di condensare gli oggetti basati su id, quantityo un'altra proprietà. Questo approccio potrebbe avere un piccolo libro scritto su di esso e richiede giustapposizione di oggetti e può diventare molto complesso. Ho scritto una piccola biblioteca per questo che è disponibile su richiesta.

Spero che questo ti aiuti!


4
  1. In Javascript non esiste la nozione di array associativo, ci sono oggetti
  2. L'unico modo per unire due oggetti è eseguire il ciclo per le loro proprietà e copiare i puntatori ai loro valori che non sono tipi e valori primitivi per tipi primitivi in ​​un'altra istanza

8
Gli oggetti in Javascript sono implementati come array associativi, quindi sicuramente esiste la stessa nozione
Dexygen,

2

Nel 2019 hai 2 buone opzioni:

Assegnazione oggetto [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

Diffusione di oggetti [ doc ]

const result = { ...baseObject, ...updatingObject};

Il primo tende ad essere più sicuro, più standard e polivalente. Un buon pro e contro qui



1

jquery ha un valore booleano per la copia profonda. Potresti fare qualcosa del genere:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

Inoltre è possibile modificare questa funzione per supportare l'unione di n-array.

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

Quindi ora puoi farlo

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

0

Avevo bisogno di una fusione di oggetti profondi. Quindi tutte le altre risposte non mi hanno aiutato molto. _.extend e jQuery.extend fanno bene, a meno che tu non abbia un array ricorsivo come me. Ma non è poi così male, puoi programmarlo in cinque minuti:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

0

Per unire le matrici in jQuery che ne dici di $ .merge?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

0

Soluzione ricorsiva (estende anche le matrici di oggetti) + null controllato

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

test

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

Ho provato a usarlo con Node JS, ma si Object.getOwnPropertyNames is not a functionbloccherà l'app.
Legoless,

Lo sto usando con un motore v8 vecchio stile all'interno dell'estensione PostgreSQL plv8. E funziona nei browser. Basta trovare un modo nel tuo motore JS di fare la stessa cosa come "hasOwnProperty". Quindi è possibile riutilizzare questa logica.
sscarduzio,

0

Ecco la soluzione migliore.

obj1.unshift.apply( obj1, obj2 );

Inoltre, obj1può crescere all'interno di un ciclo senza alcun problema. (diciamo che obj2è dinamico)

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.