web-dev-qa-db-fra.com

Fusion d'objets (tableaux associatifs)

Quelle est la meilleure façon/standard de fusionner deux tableaux associatifs en JavaScript? Est-ce que tout le monde le fait simplement en roulant sa propre boucle for?

143
Wilhelm

avec jquery vous pouvez appeler $.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

(les tableaux associés sont des objets en js)

regardez ici: http://api.jquery.com/jQuery.extend/


edit: Comme suggéré par rymo, mieux vaut le faire comme suit:

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

Comme ici, obj1 (et obj2) restent inchangés.


edit2: En 2018, le moyen de le faire est via Object.assign:

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

Si vous travaillez avec ES6, ceci peut être réalisé avec Spread Operator :

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

Maintenant, en 2016, je dirais que le meilleur moyen/standard est Object.assign ()
Pure Javascript. JQuery n'est pas nécessaire.

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

Plus d'informations, exemples et polyfill ici:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

55
Manfred

Voici comment Prototype le fait:

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

appelé comme, par exemple:

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

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

EDIT: ajouté la vérification hasOwnProperty () comme indiqué correctement par bucabay dans les commentaires

47

Rester simple...

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

Underscore a aussi une méthode extend:

Copiez toutes les propriétés dans les objets source sur le objet de destination. Comme il est en ordre, la dernière source remplacera propriétés du même nom dans les arguments précédents.

_.extend(destination, *sources) 

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

Dans dojo , la "fusion" à 2 objets/tableaux serait lang.mixin(destination, source) - vous pouvez également mélanger plusieurs sources dans une destination, etc. - voir la référence de la fonction mixin pour plus de détails.

7
Alex Martelli

Rouler soi-même 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???' });

...

Cela étend simplement un splat des objets, de manière récursive. Notez également que cette fonction récursive est TCO ( Tail-Call Optimized ) car son retour est son dernier appel.

De plus, vous voudrez peut-être propriétés ciblées . Dans ce cas, vous souhaiterez peut-être condenser des objets en fonction de id, quantity ou d'une autre propriété. Cette approche pourrait avoir un petit livre écrit à ce sujet et nécessite une juxtaposition d'objet et peut devenir très complexe. J'ai écrit une petite bibliothèque pour cela disponible sur demande.

J'espère que cela t'aides!

6
Cody

voulez-vous écraser une propriété si les noms sont les mêmes mais les valeurs ne le sont pas?

Et voulez-vous changer en permanence l'un des objets d'origine, 

ou voulez-vous un nouvel objet fusionné retourné?

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
kennebec
  1. En Javascript, il n'y a pas de notion de Tableau associatif, il y a des objets
  2. La seule façon de fusionner deux objets est d'utiliser les boucles to pour leurs propriétés et de copier les pointeurs vers leurs valeurs qui Ne sont pas des types et valeurs primitifs.
4
Sergey Ilinsky

Yahoo UI (YUI) a également une fonction d'assistance pour cela:

http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html

YAHOO.namespace('example');

YAHOO.example.set1 = { foo : "foo" };
YAHOO.example.set2 = { foo : "BAR", bar : "bar" };
YAHOO.example.set3 = { foo : "FOO", baz : "BAZ" };

var Ye = YAHOO.example;

var merged = YAHOO.lang.merge(Ye.set1, Ye.set2, Ye.set3);
1
Ben Walding

Pour fusionner des tableaux dans jQuery, qu'en est-il de $ .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

jquery a un booléen pour la copie en profondeur. Vous pourriez faire quelque chose comme ça:

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

Vous pouvez également éditer cette fonction pour prendre en charge la fusion de n-tableaux.

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;                
};

Alors maintenant tu peux faire

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
demosthenes

En 2019, vous avez 2 bonnes options:

Objet assignant [ doc ]

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

Propagation d'objet [ doc ]

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

Le premier a tendance à être plus sûr, plus standard et polyvalent. Un bon pour et contre ici

0
VincentPerrin.com

Voici la meilleure solution.

obj1.unshift.apply( obj1, obj2 );

De plus, obj1 peut se développer dans une boucle sans aucun problème. (disons que obj2 est dynamique)

0
bilen

Solution récursive (étend également les tableaux d'objets) + null vérifié

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;
};

Des tests

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 }
0
sscarduzio

J'avais besoin d'une fusion d'objet profond. Donc, toutes les autres réponses ne m'ont pas beaucoup aidé. _.extend et jQuery.extend font bien, sauf si vous avez un tableau récursif comme moi. Mais ce n'est pas si grave, vous pouvez le programmer en cinq minutes:

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
Rasmus