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.