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


Necesito poder unir 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 sabe de una manera integrada para hacer esto? No necesito recursión, y no necesito fusionar funciones, solo métodos en objetos planos.


1826


origen


Respuestas:


Método estándar ECMAScript 2018

Utilizarías objeto extendido:

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

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

(ver Referencia de JavaScript de MDN)


Método para ES5 y anterior

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

Tenga en cuenta que esto simplemente agregará todos los atributos de obj2 a obj1 que podría no ser lo que quieres si todavía quieres usar el no modificado obj1.

Si estás usando un framework que craps en todos tus prototipos, entonces tienes que ser más elegante con cheques 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;
}

1886



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

Tomado de la documentación 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 quieres crear un nuevo objeto sin modificar ninguno de los argumentos, usa 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.

1114



los Harmony ECMAScript 2015 (ES6) especifica Object.assign que hará esto

Object.assign(obj1, obj2);

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


310



Busqué en Google el código para fusionar las propiedades del objeto y terminé aquí. Sin embargo, dado que no había ningún código para la fusión recursiva, lo escribí yo mismo. (Tal vez jQuery extender es recursivo por cierto?) De todos modos, con suerte, alguien más lo encontrará ú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 } } };

226



Tenga en cuenta que underscore.jses extend-método lo hace de una sola línea:

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

166



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

80



Necesito fusionar objetos hoy, y esta pregunta (y respuestas) me ayudó mucho. Probé algunas de las respuestas, pero ninguna de ellas se ajustaba a mis necesidades, así que combiné algunas de las respuestas, agregué algo y obtuve una nueva función de fusió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 ejemplos de uso:

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

58



Puedes usar propiedades de propagación de objetos-actualmente una propuesta ECMAScript de etapa 3.

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);


43



Las soluciones dadas deberían modificarse para verificar source.hasOwnProperty(property) en el for..in bucles antes de asignar; de lo contrario, terminas copiando las propiedades de toda la cadena de prototipos, que rara vez se desea ...


37



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

Un Object.assign método es parte del estándar ECMAScript 2015 (ES6) y hace exactamente lo que necesita. (IE No soportado)

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

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

Lee mas...

los polyfill para admitir navegadores 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;
    }
  });
}

33