Comment fusionner dynamiquement les propriétés de deux objets JavaScript?

je dois pouvoir fusionner deux objets JavaScript (très simples) à l'exécution. Par exemple, je voudrais:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

quelqu'un aurait-il un script pour cette ou connaissez un construit dans la façon de le faire? Je n'ai pas besoin de récursion, et je n'ai pas besoin de fusionner des fonctions, juste des méthodes sur des objets plats.

1905
demandé sur JC Grubbs 2008-10-05 04:30:54

30 réponses

ECMAScript 2018 Standard Method

Vous devez utiliser objets répartis :

let merged = {...obj1, ...obj2};

/** There's no limit to the number of objects you can merge.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};

ECMAScript 2015 (ES6) standard Method

/* For the case in question, you would do: */
Object.assign(obj1, obj2);

/** There's no limit to the number of objects you can merge.
 *  All objects get merged into the first object. 
 *  Only the object in the first argument is mutated and returned.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);

(voir référence JavaScript MDN )


méthode pour ES5 et avant

for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }

notez que cela ajoutera simplement tous les attributs de obj2 à obj1 qui pourraient ne pas être ce que vous voulez si vous voulez toujours utiliser le obj1 non modifié .

si vous utilisez un cadre qui enveloppe tous vos prototypes , alors vous devez obtenir plus de fantaisie avec des vérifications comme hasOwnProperty , mais ce code fonctionnera pour 99% des cas.

exemple de fonction:

/**
 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
 * @param obj1
 * @param obj2
 * @returns obj3 a new object based on obj1 and obj2
 */
function merge_options(obj1,obj2){
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
}
2026
répondu Derek Ziemba 2018-07-06 23:13:17

jQuery a également une utilité pour cela: http://api.jquery.com/jQuery.extend / .

tiré de la documentation de jQuery:

// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options  = { validate: true, name: "bar" };
jQuery.extend(settings, options);

// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }

le code ci-dessus mutera le objet existant nommé settings .


si vous voulez créer un nouvel objet sans modifier l'un ou l'autre des arguments, utilisez ceci:

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };

/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);

// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
1127
répondu Avdi 2018-07-19 18:28:10

le Harmony ECMAScript 2015 (ES6) précise Object.assign ce qui va le faire.

Object.assign(obj1, obj2);

le soutien de navigateur actuel est obtenir mieux , mais si vous développez pour les navigateurs qui n'ont pas de soutien, vous pouvez utiliser un polyfill .

315
répondu NanoWizard 2016-08-08 19:12:47

j'ai cherché sur Google le code pour fusionner les propriétés des objets et j'ai fini ici. Mais comme il n'y avait pas de code pour la fusion récursive, je l'ai écrit moi-même. (Peut-être que jQuery extend est récursif BTW? Quoi qu'il en soit, espérons que quelqu'un d'autre le trouvera aussi utile.

(maintenant le code n'utilise pas Object.prototype :)

Code

/*
* Recursively merge properties of two objects 
*/
function MergeRecursive(obj1, obj2) {

  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}

un exemple

o1 = {  a : 1,
        b : 2,
        c : {
          ca : 1,
          cb : 2,
          cc : {
            cca : 100,
            ccb : 200 } } };

o2 = {  a : 10,
        c : {
          ca : 10,
          cb : 20, 
          cc : {
            cca : 101,
            ccb : 202 } } };

o3 = MergeRecursive(o1, o2);

produit un objet o3 comme

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };
233
répondu Markus 2013-05-09 15:16:33

Note que underscore.js 's extend -méthode est-ce dans un one-liner:

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
167
répondu Industrial 2016-10-25 21:39:21

similaire à jQuery extend (), vous avez la même fonction dans AngularJS :

// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options  = {validate: true, name: "bar"};
angular.extend(settings, options);
81
répondu AndreasE 2016-10-25 21:52:40

j'ai besoin de fusionner des objets d'aujourd'hui, et cette question (et réponses) m'a beaucoup aidé. J'ai essayé certaines des réponses, mais aucune d'elles ne correspond à mes besoins, donc j'ai combiné certaines des réponses, ajouté quelque chose moi-même et est venu avec une nouvelle fonction de fusion. Le voici:

var merge = function() {
    var obj = {},
        i = 0,
        il = arguments.length,
        key;
    for (; i < il; i++) {
        for (key in arguments[i]) {
            if (arguments[i].hasOwnProperty(key)) {
                obj[key] = arguments[i][key];
            }
        }
    }
    return obj;
};

quelques exemples d'usages:

var t1 = {
    key1: 1,
    key2: "test",
    key3: [5, 2, 76, 21]
};
var t2 = {
    key1: {
        ik1: "hello",
        ik2: "world",
        ik3: 3
    }
};
var t3 = {
    key2: 3,
    key3: {
        t1: 1,
        t2: 2,
        t3: {
            a1: 1,
            a2: 3,
            a4: [21, 3, 42, "asd"]
        }
    }
};

console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
60
répondu Emre Erkan 2016-10-25 21:24:33

vous pouvez utiliser object spread properties - actuellement une proposition ECMAScript de stade 3.

const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
43
répondu Jaime Asm 2017-02-02 13:07:59

les solutions données doivent être modifiées pour vérifier source.hasOwnProperty(property) dans les boucles for..in avant d'attribuer - sinon, vous finissez par copier les propriétés de l'ensemble de la chaîne prototype, ce qui est rarement désiré...

37
répondu Christoph 2008-12-21 13:29:04

fusionner les propriétés de N objets dans une ligne de code

une méthode Object.assign fait partie de la norme ECMAScript 2015 (ES6) et fait exactement ce dont vous avez besoin. ( IE non supporté)

var clone = Object.assign({}, obj);

L'Objet.assign() la méthode est utilisée pour copier les valeurs de toutes les propriétés propres énumérables d'un ou plusieurs objets source vers un objet cible.

plus d'informations...

Le polyfill pour soutenir les anciens navigateurs:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
34
répondu Eugene Tiurin 2017-05-02 10:45:07

les deux suivants sont probablement un bon point de départ. lodash a également une fonction customizer pour ces besoins spéciaux!

_.extend ( http://underscorejs.org/#extend )

_.merge ( https://lodash.com/docs#merge )

29
répondu appsmatics 2016-10-25 21:58:04

au fait, ce que vous faites, c'est écraser les propriétés, pas fusionner...

Voici comment JavaScript objects area a réellement fusionné: seules les clés de l'objet to qui ne sont pas des objets eux-mêmes seront écrasées par from . Tout le reste sera réellement fusionné . Bien sûr, vous pouvez modifier ce comportement pour ne pas écraser tout ce qui existe comme si to[n] is undefined , etc...:

var realMerge = function (to, from) {

    for (n in from) {

        if (typeof to[n] != 'object') {
            to[n] = from[n];
        } else if (typeof from[n] == 'object') {
            to[n] = realMerge(to[n], from[n]);
        }
    }
    return to;
};

Utilisation:

var merged = realMerge(obj1, obj2);
22
répondu Andreas Linden 2016-10-25 21:43:42

Voici mon coup de poignard qui

  1. supporte la fusion profonde
  2. ne mute pas les arguments
  3. prend un nombre quelconque d'arguments
  4. N'étend pas l'objet prototype
  5. Ne dépend pas d'une autre bibliothèque ( jQuery , MooTools , trait de Soulignement.js , etc.)
  6. comprend le contrôle hasOwnProperty
  7. Est court :)

    /*
        Recursively merge properties and return new object
        obj1 &lt;- obj2 [ &lt;- ... ]
    */
    function merge () {
        var dst = {}
            ,src
            ,p
            ,args = [].splice.call(arguments, 0)
        ;
    
        while (args.length > 0) {
            src = args.splice(0, 1)[0];
            if (toString.call(src) == '[object Object]') {
                for (p in src) {
                    if (src.hasOwnProperty(p)) {
                        if (toString.call(src[p]) == '[object Object]') {
                            dst[p] = merge(dst[p] || {}, src[p]);
                        } else {
                            dst[p] = src[p];
                        }
                    }
                }
            }
        }
    
       return dst;
    }
    

exemple:

a = {
    "p1": "p1a",
    "p2": [
        "a",
        "b",
        "c"
    ],
    "p3": true,
    "p5": null,
    "p6": {
        "p61": "p61a",
        "p62": "p62a",
        "p63": [
            "aa",
            "bb",
            "cc"
        ],
        "p64": {
            "p641": "p641a"
        }
    }
};

b = {
    "p1": "p1b",
    "p2": [
        "d",
        "e",
        "f"
    ],
    "p3": false,
    "p4": true,
    "p6": {
        "p61": "p61b",
        "p64": {
            "p642": "p642b"
        }
    }
};

c = {
    "p1": "p1c",
    "p3": null,
    "p6": {
        "p62": "p62c",
        "p64": {
            "p643": "p641c"
        }
    }
};

d = merge(a, b, c);


/*
    d = {
        "p1": "p1c",
        "p2": [
            "d",
            "e",
            "f"
        ],
        "p3": null,
        "p5": null,
        "p6": {
            "p61": "p61b",
            "p62": "p62c",
            "p63": [
                "aa",
                "bb",
                "cc"
            ],
            "p64": {
                "p641": "p641a",
                "p642": "p642b",
                "p643": "p641c"
            }
        },
        "p4": true
    };
*/
19
répondu Paul Spaulding 2017-04-18 10:21:54

objet.attribuer()

ECMAScript 2015 (ES6)

il s'agit d'une nouvelle technologie, faisant partie de la norme ECMAScript 2015 (ES6). Les spécifications de cette technologie ont été finalisées, mais vérifiez la table de compatibilité pour l'utilisation et l'état de mise en œuvre dans divers navigateurs.

L'Objet.assignez () la méthode est utilisée pour copier les valeurs de toutes les propriétés propres énumérables d'un ou plus d'objets source vers un objet cible. Il sera de retour de l'objet cible.

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 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.
16
répondu Reza Roshan 2015-11-16 16:35:04

Pour ne pas-trop-compliqué objets, vous pourriez utiliser JSON :

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;

objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);

// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}

objMerge = objMerge.replace(/\}\{/, ","); //  \_ replace with comma for valid JSON

objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/

rappelez-vous que dans cet exemple "}{" ne doit pas se produire dans une chaîne!

16
répondu Algy 2017-10-28 12:31:07

la meilleure façon pour vous de faire ceci est d'ajouter une propriété correcte qui est non-énumérable en utilisant L'objet.defineProperty.

de cette façon, vous serez encore en mesure d'itérer sur vos propriétés d'objets sans avoir le" extend " nouvellement créé que vous obtiendriez si vous deviez créer la propriété avec Objet.prototype.étendre.

Espérons que cela aide:

Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

une fois que vous avez ce travail, vous pouvez faire:

var obj = {
    name: 'stack',
    finish: 'overflow'
}
var replacement = {
    name: 'stock'
};

obj.extend(replacement);

je viens d'écrire un billet de blog à ce sujet ici: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js

13
répondu David Coallier 2010-11-09 22:09:35

vous pouvez simplement utiliser jQuery extend

var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };

jQuery.extend(obj1, obj2);

Maintenant obj1 contient toutes les valeurs de obj1 et obj2

13
répondu Dinusha 2016-03-01 10:49:04

il y a une bibliothèque appelée deepmerge sur GitHub : cela semble obtenir une certaine traction. Il s'agit d'une application autonome, disponible par l'intermédiaire des gestionnaires de paquets npm et bower.

je serais enclin à utiliser ou à améliorer ce code au lieu de copier-coller des réponses.

12
répondu Peter Mortensen 2016-10-25 21:56:15

Juste, si quelqu'un est à l'aide de Google Fermeture de la Bibliothèque :

goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};

fonction d'aide similaire existe pour le tableau :

var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
10
répondu orian 2016-10-25 21:40:54

Prototype a ceci:

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

obj1.extend(obj2) fera ce que vous voulez.

8
répondu ephemient 2016-10-25 20:26:12

j'ai étendu la méthode de David Coallier:

  • ajouté la possibilité de fusionner plusieurs objets
  • supporte des objets profonds
  • paramètre override (qui est détecté si le dernier paramètre est un booléen)

si override est false, aucune propriété n'est annulée mais de nouvelles propriétés seront ajoutées.

Usage: obj.de fusion(fusion... [, outrepasser]);

Voici mon code:

Object.defineProperty(Object.prototype, "merge", {
    enumerable: false,
    value: function () {
        var override = true,
            dest = this,
            len = arguments.length,
            props, merge, i, from;

        if (typeof(arguments[arguments.length - 1]) === "boolean") {
            override = arguments[arguments.length - 1];
            len = arguments.length - 1;
        }

        for (i = 0; i < len; i++) {
            from = arguments[i];
            if (from != null) {
                Object.getOwnPropertyNames(from).forEach(function (name) {
                    var descriptor;

                    // nesting
                    if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
                            && typeof(from[name]) === "object") {

                        // ensure proper types (Array rsp Object)
                        if (typeof(dest[name]) === "undefined") {
                            dest[name] = Array.isArray(from[name]) ? [] : {};
                        }
                        if (override) {
                            if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
                                dest[name] = [];
                            }
                            else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
                                dest[name] = {};
                            }
                        }
                        dest[name].merge(from[name], override);
                    } 

                    // flat properties
                    else if ((name in dest && override) || !(name in dest)) {
                        descriptor = Object.getOwnPropertyDescriptor(from, name);
                        if (descriptor.configurable) {
                            Object.defineProperty(dest, name, descriptor);
                        }
                    }
                });
            }
        }
        return this;
    }
});

des Exemples et des cas de tests:

function clone (obj) {
    return JSON.parse(JSON.stringify(obj));
}
var obj = {
    name : "trick",
    value : "value"
};

var mergeObj = {
    name : "truck",
    value2 : "value2"
};

var mergeObj2 = {
    name : "track",
    value : "mergeObj2",
    value2 : "value2-mergeObj2",
    value3 : "value3"
};

assertTrue("Standard", clone(obj).merge(mergeObj).equals({
    name : "truck",
    value : "value",
    value2 : "value2"
}));

assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
    name : "trick",
    value : "value",
    value2 : "value2"
}));

assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
    name : "track",
    value : "mergeObj2",
    value2 : "value2-mergeObj2",
    value3 : "value3"
}));

assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
    name : "trick",
    value : "value",
    value2 : "value2",
    value3 : "value3"
}));

var deep = {
    first : {
        name : "trick",
        val : "value"
    },
    second : {
        foo : "bar"
    }
};

var deepMerge = {
    first : {
        name : "track",
        anotherVal : "wohoo"
    },
    second : {
        foo : "baz",
        bar : "bam"
    },
    v : "on first layer"
};

assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
    first : {
        name : "track",
        val : "value",
        anotherVal : "wohoo"
    },
    second : {
        foo : "baz",
        bar : "bam"
    },
    v : "on first layer"
}));

assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
    first : {
        name : "trick",
        val : "value",
        anotherVal : "wohoo"
    },
    second : {
        foo : "bar",
        bar : "bam"
    },
    v : "on first layer"
}));

var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));

obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));

var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));

var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);


var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));

// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];

a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));

a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));

a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));

a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));

a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));

a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));

la méthode mes égaux peut être trouvée ici: comparaison D'objet en JavaScript

7
répondu gossi 2017-05-23 12:26:35

dans MooTools , il y a objet.merge () :

Object.merge(obj1, obj2);
7
répondu philfreo 2016-10-25 20:29:53

la fusion d'objets est simple.

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}


var mergedObj = Object.assign(obj1,obj2,obj3)

console.log(mergedObj);

les objets sont fusionnés de droite à gauche, ce qui signifie que les objets ayant des propriétés identiques à celles des objets à leur droite seront remplacés.

dans cet exemple, obj2.car l'emporte sur obj1.car

7
répondu Legends 2018-05-26 15:24:09

Dans Ext JS 4, il peut être fait comme suit:

var mergedObject = Ext.Object.merge(object1, object2)

// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)

voir Fusion( objet ) : Objet .

6
répondu Mark 2016-10-25 20:40:00

Avec Souligné.js , pour fusionner un tableau d'objets faire:

var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ];
_(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); });

il en résulte:

Object {a: 1, b: 2, c: 3, d: 4}
5
répondu devmao 2016-10-25 21:53:24

Basé sur Markus' et vsync " réponse , c'est une version élargie. La fonction prend n'importe quel nombre d'arguments. Il peut être utilisé pour définir les propriétés sur les noeuds DOM et fait des copies profondes des valeurs. Toutefois, le premier argument est donnée par référence.

pour détecter un nœud DOM, la fonction isDOMNode() est utilisée (voir la question sur le débordement de la pile isDOM JavaScript-Comment faire vous vérifiez si un objet JavaScript est un objet DOM? )

il a été testé dans Opera 11, Firefox 6, Internet Explorer 8 et Google Chrome 16.

Code

function mergeRecursive() {

  // _mergeRecursive does the actual job with two arguments.
  var _mergeRecursive = function (dst, src) {
    if (isDOMNode(src) || typeof src !== 'object' || src === null) {
      return dst;
    }

    for (var p in src) {
      if (!src.hasOwnProperty(p))
        continue;
      if (src[p] === undefined)
        continue;
      if ( typeof src[p] !== 'object' || src[p] === null) {
        dst[p] = src[p];
      } else if (typeof dst[p]!=='object' || dst[p] === null) {
        dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
      } else {
        _mergeRecursive(dst[p], src[p]);
      }
    }
    return dst;
  }

  // Loop through arguments and merge them into the first argument.
  var out = arguments[0];
  if (typeof out !== 'object' || out === null)
    return out;
  for (var i = 1, il = arguments.length; i < il; i++) {
    _mergeRecursive(out, arguments[i]);
  }
  return out;
}

quelques exemples

Set innerHTML et le style d'un Élément HTML

mergeRecursive(
  document.getElementById('mydiv'),
  {style: {border: '5px solid green', color: 'red'}},
  {innerHTML: 'Hello world!'});

fusionner des tableaux et des objets. Notez que l'indéfini peut être utilisé pour préserver les valeurs dans le tableau de gauche/objet.

o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}

tout argument n'étant pas un objet JavaScript (y compris null) sera ignoré. Sauf pour le premier argument, les noeuds DOM sont également rejetés. Attention: les chaînes créées comme new String() sont en fait des objets.

o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}

si vous voulez fusionner deux objets dans une nouvelle (sans affecter aucun des deux) fourniture {} comme premier argument

var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false

Modifier (par ReaperSoon):

Pour fusionner des tableaux

function mergeRecursive(obj1, obj2) {
  if (Array.isArray(obj2)) { return obj1.concat(obj2); }
  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = mergeRecursive(obj1[p], obj2[p]);
      } else if (Array.isArray(obj2[p])) {
        obj1[p] = obj1[p].concat(obj2[p]);
      } else {
        obj1[p] = obj2[p];
      }
    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];
    }
  }
  return obj1;
}
5
répondu Snoozer Man 2017-11-06 21:27:02

vous devez utiliser lodash defaultsDeep

_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
4
répondu Raphaël 2015-12-22 11:02:49

il est intéressant de mentionner que la version du 140byt.ES collection est la résolution de la tâche dans un minimum d'espace et vaut la peine d'un essai à cette fin:

Code:

function m(a,b,c){for(c in b)b.hasOwnProperty(c)&&((typeof a[c])[0]=='o'?m(a[c],b[c]):a[c]=b[c])}

l'Utilisation de votre but:

m(obj1,obj2);

voici le original Gist .

4
répondu pagid 2016-10-25 21:45:26

j'utilise ce qui suit qui est en JavaScript pur. Il part de l'argument le plus juste et les combine jusqu'au premier argument. Il n'y a pas de valeur de retour, seul le premier argument est modifié et le paramètre left-most (sauf le premier) a le plus de poids sur les propriétés.

var merge = function() {
  var il = arguments.length;

  for (var i = il - 1; i > 0; --i) {
    for (var key in arguments[i]) {
      if (arguments[i].hasOwnProperty(key)) {
        arguments[0][key] = arguments[i][key];
      }
    }
  }
};
3
répondu Etherealone 2016-10-25 22:01:59

Wow.. c'est le premier StackOverflow post que j'ai vu avec plusieurs pages. Toutes nos excuses pour avoir ajouté une autre "réponse "

cette méthode est pour ES5 & Earlier - Il ya beaucoup d'autres réponses traitant ES6.

Je n'ai vu aucun " deep " objet de fusion utilisant la arguments propriété. Voici ma réponse - compact & recursive , permettant de passer des arguments d'objet illimités:

function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        // if (arguments[i].constructor !== Object) continue;
        for (var k in arguments[i]) {
            if (arguments[i].hasOwnProperty(k)) {
                o[k] = arguments[i][k].constructor === Object ? extend(o[k] || {}, arguments[i][k]) : arguments[i][k];
            }
        }
    }
    return o;
}

la partie commentée est facultative .. il sautera simplement les arguments passés qui ne sont pas des objets (empêchant les erreurs).

exemple:

extend({
    api: 1,
    params: {
        query: 'hello'
    }
}, {
    params: {
        query: 'there'
    }
});

// outputs {api: 1, params: {query: 'there'}}

Cette réponse n'est qu'une goutte dans l'océan ...

3
répondu Logan 2018-05-01 18:44:14