¿Cómo puedo fusionar propiedades de dos objetos JavaScript de forma dinámica?

2842

Necesito poder fusionar dos objetos JavaScript (muy simples) en tiempo de ejecución. Por ejemplo, me gustaría:

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

obj1.merge(obj2);

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

¿Alguien tiene un script para esto o conoce una forma incorporada para hacer esto? No necesito recursividad y no necesito fusionar funciones, solo métodos en objetos planos.

3
  • Vale la pena señalar esta respuesta a una pregunta similar , que muestra cómo fusionar "un nivel hacia abajo". Es decir, fusiona valores de claves duplicadas (en lugar de sobrescribir el primer valor con el segundo valor), pero no se repite más allá de eso. En mi humilde opinión, es un buen código limpio para esa tarea. ToolmakerSteve 3 oct 2019 a las 21:42
  • Por cierto, las primeras respuestas hacen una fusión "superficial": si la misma clave existe tanto en obj1 como en obj2, el valor en obj2 se mantiene, el valor en obj1 se elimina. Por ejemplo, si el ejemplo de la pregunta lo hubiera hecho var obj2 = { animal: 'dog', food: 'bone' };, la fusión sería { food: 'bone', car: 'ford', animal: 'dog' }. Si está trabajando con "datos anidados" y desea una "combinación profunda", busque respuestas que mencionen "combinación profunda" o "recursividad". Si tiene valores que lo son arrays, utilice la opción "arrayMerge" de github "TehShrike / deepmerge", como se menciona aquí . ToolmakerSteve 4 oct 2019 a las 12:30
  • Siga el siguiente enlace stackoverflow.com/questions/171251/… El operador de propagación, que es la nueva característica en la versión ES6Soura Sankar Ghosh 11 ene.20 a las 13:00
3410

Método estándar ECMAScript 2018

Se podría utilizar objeto propagación :

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

mergedes ahora la unión de obj1y obj2. Las propiedades de obj2sobrescribirán las de obj1.

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

Aquí también está la documentación de MDN para esta sintaxis. Si está utilizando babel, necesitará el complemento babel-plugin-transform-object-rest-spread para que funcione.

Método estándar ECMAScript 2015 (ES6)

/* 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);

(consulte la referencia de JavaScript de MDN )


Método para ES5 y versiones anteriores

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

Tenga en cuenta que esto simplemente agregará todos los atributos de obj2a lo obj1que podría no ser lo que desea si aún desea usar el sin modificar obj1.

Si está utilizando un marco que se caga en todos sus prototipos, entonces tiene que ser más sofisticado con comprobaciones como hasOwnProperty, pero ese código funcionará en el 99% de los casos.

Función de ejemplo:

/**
 * 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;
}
3
  • 106
    Esto no funciona si los objetos tienen atributos del mismo nombre y también querrá fusionar los atributos. Xiè Jìléi 24/10/10 a las 10:56
  • 77
    Esto solo hace una copia / fusión superficial. Tiene el potencial de aplastar muchos elementos. Jay Taylor 2/06/11 a las 15:39
  • 56
    +1 por reconocer que algunas pobres almas se ven obligadas a usar marcos que cagan en todos sus prototipos ...thejonwithnoh 7 de mayo de 2016 a las 4:18
1216

jQuery también tiene una utilidad para esto: http://api.jquery.com/jQuery.extend/ .

Tomado de la documentación 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" }

El código anterior mutará el objeto existente llamado settings.


Si desea crear un nuevo objeto sin modificar ninguno de los argumentos, use esto:

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.
2
  • 169
    Atención: la variable "configuración", sin embargo, se modificará. jQuery no devuelve una nueva instancia. La razón de esto (y del nombre) es que .extend () fue desarrollado para extender objetos, en lugar de mezclar cosas juntas. Si desea un nuevo objeto (por ejemplo, la configuración es la predeterminada que no desea tocar), siempre puede jQuery.extend ({}, configuración, opciones); webmat 4 de mayo de 2011 a las 16:01
  • 28
    Eso sí, jQuery.extend también tiene una configuración profunda (booleana). jQuery.extend(true,settings,override), lo cual es importante si una propiedad en la configuración contiene un objeto y la anulación solo tiene una parte de ese objeto. En lugar de eliminar las propiedades incomparables, la configuración profunda solo se actualizará donde exista. El valor predeterminado es falso. vol7ron 9 de junio de 2011 a las 21:09
369

La Armonía EcmaScript 2015 (ES6) especifica Object.assignque hacer esto.

Object.assign(obj1, obj2);

El soporte actual del navegador está mejorando , pero si está desarrollando para navegadores que no tienen soporte, puede usar un polyfill .

4
  • 39
    Tenga en cuenta que esta es solo una fusión superficialJoachim Lous 16 de marzo de 2016 a las 10:04
  • Mientras tanto, creo que Object.assigntiene una cobertura bastante decente: kangax.github.io/compat-table/es6/…brass monkey 26 de mayo de 2016 a las 15:38
  • 13
    Esta debería ser ahora la respuesta correcta. Hoy en día, la gente compila su código para que sea compatible con el raro navegador (IE11) que no admite este tipo de cosas. Nota al margen: si no desea agregar obj2 a obj1, puede devolver un nuevo objeto usandoObject.assign({}, obj1, obj2)Duvrai 21/07/2016 a las 20:02
  • 6
    @Duvrai Según los informes que he visto, IE11 definitivamente no es raro en alrededor del 18% de la participación de mercado en julio de 2016.NanoWizard 8 de agosto de 2016 a las 19:15
281

Busqué en Google código para fusionar propiedades de objetos y terminé aquí. Sin embargo, como no había ningún código para la fusión recursiva, lo escribí yo mismo. (¿Quizás jQuery extend sea recursivo por cierto?) De todos modos, es de esperar que alguien más lo encuentre útil también.

(Ahora el código no usa Object.prototype:)

Código

/*
* 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 ejemplo

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

Produce el objeto o3 como

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };
1
  • 11
    Bien, pero primero haría una copia profunda de los objetos. De esta manera, o1 también se modificaría, ya que los objetos se pasan por referencia. skerit 16 de enero de 2011 a las 16:00
179

Tenga en cuenta que underscore.jsel extendmétodo- s hace esto en una sola línea:

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
1
  • 38
    Este ejemplo está bien ya que se trata de objetos anónimos, pero si este no es el caso, el comentario de webmat en la advertencia de respuesta de jQuery sobre mutaciones se aplica aquí, ya que el subrayado también muta el objeto de destino . Al igual que la respuesta de jQuery, para hacer esto sin mutaciones, simplemente fusione en un objeto vacío:_({}).extend(obj1, obj2);Abe Voelker 5/06/12 a las 18:12
84

Similar a jQuery extend (), tiene la misma función en 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);
0
67

Necesito fusionar objetos hoy, y esta pregunta (y sus respuestas) me ayudaron mucho. Probé algunas de las respuestas, pero ninguna se ajustaba a mis necesidades, así que combiné algunas de las respuestas, agregué algo yo mismo y se me ocurrió una nueva función de combinación. Aquí está:

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

Algunos usos de ejemplo:

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 }));
0
59

Puede utilizar la sintaxis de propagación de objetos para lograr esto. Es parte de ES2018 y más allá.

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
4
  • ¿Soporte de navegador? Slava 11/10/2017 a las 10:01
  • 1
    @ Alph.Dev ¿Conoces caniuse.com? connexo 2 de enero de 2018 a las 10:32
  • 1
    No puedo hacer que la sintaxis de 3 puntos funcione en node.js. nodo se queja de ello. klewis 16/03/18 a las 19:52
  • ¿Qué representa ... (3 puntos)? Merrin K 21 de agosto a las 5:34
43

Fusionar propiedades de N objetos en una línea de código

Un Object.assignmétodo es parte del estándar ECMAScript 2015 (ES6) y hace exactamente lo que necesita. ( IEno soportado)

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

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

Lee mas...

El polyfill para admitir navegadores más antiguos:

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;
    }
  });
}
0
42

Las soluciones dadas deben modificarse para verificar source.hasOwnProperty(property)los for..inbucles antes de asignar; de lo contrario, terminará copiando las propiedades de toda la cadena del prototipo, lo que rara vez se desea ...

0
36

Los dos siguientes son probablemente un buen punto de partida. ¡lodash también tiene una función de personalización para esas necesidades especiales!

_.extend( http://underscorejs.org/#extend )
_.merge( https://lodash.com/docs#merge )

0
30

Por cierto, lo que estáis haciendo es sobrescribir propiedades, no fusionar ...

Así es como se fusionan realmente los objetos de JavaScript: solo tose sobrescribirán las claves del objeto que no sean objetos en sí mismos from. Todo lo demás se fusionará realmente . Por supuesto, puede cambiar este comportamiento para no sobrescribir nada que exista como solo 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;
};

Uso:

var merged = realMerge(obj1, obj2);
0
29

Aquí está mi puñalada que

  1. Admite fusión profunda
  2. No muta argumentos
  3. Acepta cualquier número de argumentos
  4. No amplía el prototipo del objeto.
  5. No depende de otra biblioteca ( jQuery , MooTools , Underscore.js , etc.)
  6. Incluye cheque para hasOwnProperty
  7. Es corto :)

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

Ejemplo:

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
    };
*/
0
20

Object.assign ()

ECMAScript 2015 (ES6)

Esta es una nueva tecnología, parte del estándar ECMAScript 2015 (ES6). La especificación de esta tecnología se ha finalizado, pero consulte la tabla de compatibilidad para conocer el estado de uso e implementación en varios navegadores.

El método Object.assign () se utiliza para copiar los valores de todas las propiedades propias enumerables de uno o más objetos de origen a un objeto de destino. Devolverá el objeto de destino.

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.
20

Para objetos no demasiado complicados, puede usar 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_/

Tenga en cuenta que en este ejemplo "} {" no debe aparecer dentro de una cadena.

0
18

Hay una biblioteca llamada deepmergeen GitHub : Eso parece estar recibiendo algo de tracción. Es independiente, disponible a través de los administradores de paquetes npm y bower .

Me inclinaría a usar o mejorar esto en lugar de copiar y pegar el código de las respuestas.

17

La mejor manera de hacerlo es agregar una propiedad adecuada que no sea enumerable mediante Object.defineProperty.

De esta manera, aún podrá iterar sobre las propiedades de sus objetos sin tener la "extensión" recién creada que obtendría si creara la propiedad con Object.prototype.extend.

Ojalá esto ayude:

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

Una vez que tenga eso funcionando, puede hacer:

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

obj.extend(replacement);

Acabo de escribir una publicación de blog al respecto aquí: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js

0
16

Simplemente puede usar jQuery extend

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

jQuery.extend(obj1, obj2);

Ahora obj1contiene todos los valores de obj1yobj2

0
15

El prototipo tiene esto:

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

obj1.extend(obj2) harás lo que quieras.

0
13

** Fusionar objetos es simple usando Object.assigno el ...operador de propagación **

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


var mergedObj = Object.assign(obj1,obj2,obj3)
 // or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}

console.log(mergedObj);

Los objetos se fusionan de derecha a izquierda, esto significa que los objetos que tienen propiedades idénticas a los objetos a su derecha serán anulados.

En este ejemplo obj2.caranulaobj1.car

12

Solo si alguien está usando Google Closure Library :

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

Existe una función auxiliar similar para la matriz :

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'
0
12

Wow ... esta es la primera publicación de StackOverflow que he visto con varias páginas. Disculpas por agregar otra "respuesta"


ES5 y anteriores

Este método es para ES5 y versiones anteriores ; hay muchas otras respuestas que abordan ES6.

No vi ningún objeto "profundo" que se fusionara utilizando la argumentspropiedad. Aquí está mi respuesta: compacta y recursiva , que permite pasar argumentos de objeto ilimitados:

function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        // Uncomment to skip arguments that are not objects (to prevent errors)
        // 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;
}

Ejemplo

/**
 * Extend objects
 */
function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        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;
}

/**
 * Example
 */
document.write(JSON.stringify(extend({
    api: 1,
    params: {
        query: 'hello'
    }
}, {
    params: {
        query: 'there'
    }
})));
// outputs {"api": 1, "params": {"query": "there"}}

Esta respuesta es ahora solo una gota en el océano ...

0
11

Amplié el método de David Coallier:

  • Añadida la posibilidad de fusionar varios objetos.
  • Soporta objetos profundos
  • anular parámetro (que se detecta si el último parámetro es un booleano)

Si invalidar es falso, no se invalida ninguna propiedad, pero se agregarán nuevas propiedades.

Uso: obj.merge (fusiona ... [, anular]);

Aquí está mi código:

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

Ejemplos y casos de prueba:

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]));

Mi método de igualdad se puede encontrar aquí: Comparación de objetos en JavaScript

10

En MooTools , hay Object.merge () :

Object.merge(obj1, obj2);
9

En Ext JS 4 se puede hacer de la siguiente manera:

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

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

Ver fusionar (objeto): Objeto .

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

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

Usando jQuery.extend () - Enlace

// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );

Usando _.merge () - Enlace

// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );

Usando _.extend () - Enlace

// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );

Usando Object.assign () ECMAScript 2015 (ES6) - Enlace

// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );

Salida de todos

obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
7

Según la respuesta de Markus y vsync , esta es una versión ampliada. La función acepta cualquier número de argumentos. Se puede usar para establecer propiedades en los nodos DOM y hace copias profundas de los valores. Sin embargo, el primer argumento se da por referencia.

Para detectar un nodo DOM, se utiliza la función isDOMNode () (consulte la pregunta de desbordamiento de pila JavaScript isDOM: ¿cómo se comprueba si un objeto JavaScript es un objeto DOM? )

Fue probado en Opera 11, Firefox 6, Internet Explorer 8 y Google Chrome 16.

Código

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

Algunos ejemplos

Establecer innerHTML y el estilo de un elemento HTML

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

Fusionar matrices y objetos. Tenga en cuenta que undefined se puede utilizar para conservar los valores en la matriz / objeto de la izquierda.

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

Se ignorará cualquier argumento que no sea un objeto JavaScript (incluido el valor nulo). Excepto por el primer argumento, también se descartan los nodos DOM. Tenga en cuenta que, es decir, las cadenas creadas como new String () son de hecho objetos.

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 desea fusionar dos objetos en uno nuevo (sin afectar a ninguno de los dos) proporcione {} como primer argumento

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

Editar (por ReaperSoon):

Para fusionar también matrices

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

Deberías usar los valores predeterminados de lodash

_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
5

Con Underscore.js , para fusionar una matriz de objetos, haga lo siguiente:

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

En resultado de:

Object {a: 1, b: 2, c: 3, d: 4}
5

let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);