¿Cómo puedo fusionar propiedades de dos objetos JavaScript de forma dinámica?
Frecuentes
Visto 1,443 veces
2720
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.
30 Respuestas
3206
Método estándar ECMAScript 2018
Usarías propagación del objeto:
let merged = {...obj1, ...obj2};
merged
es ahora la unión de obj1
y obj2
. Propiedades en obj2
sobrescribirá los 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á el Documentación MDN para esta sintaxis. Si está usando babel, necesitará el babel-plugin-transform-object-rest-spread plugin 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);
(consulta: 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 obj2
a obj1
que podría no ser lo que desea si aún desea utilizar el sin modificar obj1
.
Si está utilizando un marco que se caga en todos sus prototipos, entonces tiene que ser más elegante con controles 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;
}
Respondido 20 Abr '20, 10:04
Esto no funciona si los objetos tienen atributos del mismo nombre y también querrá fusionar los atributos. - Xiè Jìléi
Esto solo hace una copia / fusión superficial. Tiene el potencial de aplastar muchos elementos. - Jay Taylor
+1 por reconocer que algunas pobres almas se ven obligadas a usar marcos que cagan en todos sus prototipos ... - jonwithnoh
Esto no funcionó para mí porque "Por lo tanto, asigna propiedades en lugar de simplemente copiar o definir nuevas propiedades. Esto puede hacer que no sea adecuado para fusionar nuevas propiedades en un prototipo si las fuentes de fusión contienen captadores". (desarrollador.mozilla.org/en-US/docs/Web/JavaScript/Reference/…). Tuve que usar var merged = {...obj1, ...obj2}
. - Morgler
@ Ze'ev {...obj1, ...{animal: 'dog'}}
- barra invertida112
1208
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 quieres 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.
Respondido 19 Jul 18, 19:07
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); - tapete web
¡Tocar el asunto exacto! Gracias un montón. Como se indicó en el comentario anterior, está mal nombrado. Busqué documentos de jQuery una y otra vez y no me encontré con ellos. - mike starov
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
Caray Willikers, realmente hicieron un buen trabajo al nombrar esto. Si busca cómo extender un objeto Javascript, ¡aparece de inmediato! Sin embargo, es posible que no lo encuentre si está tratando de fusionar o unir objetos Javascript. - Derek Greer
No le diga a la gente que considere usar un método de biblioteca cuando un par de líneas de Vanilla JS harán lo que quieran. ¡Hubo un tiempo antes de jQuery! - LocoMerlín
363
EL Armonía ECMAScript 2015 (ES6) especifica Object.assign
que hará esto.
Object.assign(obj1, obj2);
La compatibilidad con el navegador actual es mejorando, pero si está desarrollando para navegadores que no son compatibles, puede utilizar una polyfill.
Respondido 08 ago 16, 20:08
Tenga en cuenta que esta es solo una fusión superficial: Joaquín Lous
Yo pienso mientras tanto Object.assign
tiene una cobertura bastante decente: kangax.github.io/compat-table/es6/… - mono de latón
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 usando Object.assign({}, obj1, obj2)
- Duvrai
@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. - Nanomago
@Kermani El OP señala específicamente que la recursividad es innecesaria. Por lo tanto, si bien es útil saber que esta solución realiza una fusión superficial, esta respuesta es suficiente tal como está. El comentario de JoachimLou ha recibido votos a favor bien merecidos y proporciona esa información adicional cuando es necesario. Creo que la diferencia entre la fusión profunda y superficial y temas similares están más allá del alcance de esta discusión y se adaptan mejor a otras preguntas de SO. - Nanomago
278
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
:)
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 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 } } };
contestado el 09 de mayo de 13 a las 16:05
Bien, pero primero haría una copia profunda de los objetos. De esta forma, o1 también se modificaría, ya que los objetos se pasan por referencia. - skerit
Esto era lo que estaba buscando. Asegúrese de verificar si obj2.hasOwnProperty (p) antes de ir a la declaración try catch. De lo contrario, podría terminar con alguna otra basura fusionada desde más arriba en la cadena de prototipos. - Adam
Gracias Markus. Tenga en cuenta que MergeRecursive también modifica o1, por lo que al final, o1 y o3 son idénticos. Puede ser más intuitivo si no devuelve nada, para que el usuario sepa que lo que está suministrando (o1) se modifica y se convierte en el resultado. Además, en su ejemplo, podría valer la pena agregar algo en o2 que no esté originalmente en o1, para mostrar que las propiedades de o2 se insertan en o1 (alguien más abajo envió un código alternativo copiando su ejemplo, pero el suyo se rompe cuando o2 contiene propiedades que no en o1 - pero el suyo funciona a este respecto). - crepe
Esta es una buena respuesta, pero con un par de objeciones: 1) Ninguna lógica debe basarse en excepciones; en este caso, cualquier excepción lanzada será detectada con resultados impredecibles. 2) Estoy de acuerdo con el comentario de @ pancake sobre no devolver nada, ya que el objeto original está modificado. Aquí hay un ejemplo de jsFiddle sin la lógica de excepción: jsfiddle.net/jlowery2663/z8at6knn/4 - Jeff Lowery - jeff lowery
Además, obj2 [p] .constructor == Array es necesario en cualquier caso donde haya un arreglo de objetos. - El compositor
178
Tenga en cuenta que underscore.js
's extend
-método hace esto en una sola línea:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Respondido 25 Oct 16, 22:10
Este ejemplo está bien ya que está tratando con objetos anónimos, pero si este no es el caso, entonces el webmat comentar en la respuesta de jQuery La advertencia sobre mutaciones se aplica aquí, como 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
Hay otro que puede ser relevante según lo que intente lograr: _.defaults(object, *defaults)
"Complete las propiedades nulas e indefinidas en el objeto con valores de los objetos predeterminados y devuelva el objeto". - conny
Muchas personas han comentado sobre la mutación del objeto de destino, pero en lugar de que un método cree uno nuevo, un patrón común (en dojo, por ejemplo) es decir dojo.mixin (dojo.clone (myobj), {newpropertys: "para agregar a myobj "}) - colin d
El subrayado puede tomar un número arbitrario de objetos, por lo que puede evitar la mutación del objeto original haciendo var mergedObj = _.extend({}, obj1, obj2)
. - lobatí
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);
Respondido 25 Oct 16, 22:10
@naXa Creo que sería una opción si no desea agregar una biblioteca solo para esta fn. - juanmf
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í lo tienes:
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 }));
Respondido 25 Oct 16, 22:10
buena respuesta, pero creo que si una propiedad está presente en el primero y en el segundo y está tratando de crear un nuevo objeto fusionando primero y segundo, los únicos presentes en el primer objeto se perderán - Huelguistas
¿Pero no es el comportamiento esperado? El propósito de esta función es anular los valores en el orden de los argumentos. El siguiente anulará la corriente. ¿Cómo se pueden preservar los valores únicos? De mi ejemplo, ¿qué esperas de merge({}, t1, { key1: 1 })
? - emre erkan
Mi expectativa es fusionar solo valores sin tipo de objeto. - AGamePlayer
falla si el resultado esperado es el siguiente: gist.github.com/ceremcem/a54f90923c6e6ec42c7daf24cf2768bd - ceremonia
Esto funcionó para mí en modo estricto para mi proyecto node.js. Hasta ahora, esta es la mejor respuesta en esta publicación. - Klewis
56
Puede utilizar el sintaxis de propagación de objetos 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);
Respondido el 16 de Septiembre de 20 a las 21:09
42
Fusionar propiedades de N objetos en una línea de código
An Object.assign
El 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 utiliza para copiar los valores de todas las propiedades propias enumerables de uno o más objetos de origen a un objeto de destino.
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;
}
});
}
Respondido el 20 de junio de 20 a las 10:06
¿Qué hace el "uso estricto" en los navegadores más antiguos o por qué está ahí? navegadores que admiten object [defineProperty; llaves; getOwnPropertyDescriptor; etc], no son exactamente viejos. Son solo versiones anteriores de los AU gen.5. - bekim bacaj
Gracias por aclarar eso Objects.assign
devuelve un objeto combinado que las otras respuestas no. Ese es un estilo de programación más funcional. - Sridhar Sarnobat
41
Las soluciones dadas deben modificarse para comprobar source.hasOwnProperty(property)
en el capítulo respecto a la for..in
bucles antes de asignar; de lo contrario, terminará copiando las propiedades de toda la cadena del prototipo, lo que rara vez se desea ...
Respondido el 21 de diciembre de 08 a las 13:12
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)
Respondido 25 Oct 16, 22:10
Tenga en cuenta que los métodos anteriores mutan el objeto original. - Torre
El método lodash funcionó para mí, ya que quería fusionar dos objetos y conservar las propiedades anidadas a más de uno o dos niveles de profundidad (en lugar de simplemente reemplazarlas / borrarlas). - SamLadrillo
verdadero @Wtower. Solo tuve un error debido a esto. Lo mejor es asegurarse de que siempre comience como _.merge ({}, ... - Martín Cremer
29
Por cierto, lo que estáis haciendo es sobrescribir propiedades, no fusionar ...
Así es como se fusionó realmente el área de objetos de JavaScript: solo las claves en el to
Los objetos que no son objetos en sí mismos serán sobrescritos por from
. Todo lo demás será realmente fusionado. 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);
Respondido 25 Oct 16, 22:10
Me ayudó mucho, la extensión js de subrayado realmente se sobrescribió, en lugar de fusionarse - david cums
Vale la pena señalar que typeof array y typeof null devolverán 'objeto' y romperán esto. - Salakar
@ u01jmg3 vea mi respuesta aquí: stackoverflow.com/questions/27936772/… - la función isObject - Salakar
Esto se rompe si usa está en modo estricto para proyectos de node.js: Klewis
28
Aquí está mi puñalada que
- Admite fusión profunda
- No muta argumentos
- Acepta cualquier número de argumentos
- No amplía el prototipo del objeto.
- No depende de otra biblioteca (jQuery, MooTools, Underscore.js, Etc.)
- Incluye cheque para hasOwnProperty
Es corto :)
/* Recursively merge properties and return new object obj1 <- obj2 [ <- ... ] */ 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
};
*/
Respondido 18 Abr '17, 11:04
En comparación con las otras que probé en esta página, esta función es verdaderamente recursiva (hace una fusión profunda) e imita lo que jQuery.extend () hace realmente bien. Sin embargo, sería mejor que modificara el primer objeto / argumento para que el usuario pueda decidir si quiere pasar un objeto vacío. {}
como primer parámetro o hacer que la función modifique el objeto original. Por lo tanto, si cambias dst = {}
a dst = arguments[0]
cambiará el primer objeto que pase al objeto combinado - Jasdeep Khalsa
Ahora dejó de funcionar en Chrome. Creo que es una mala idea usar tal construcción. toString.call(src) == '[object Object]'
para comprobar si hay un objeto o no. typeof src
es mucho mejor. Además, transforma las matrices en objetos (al menos tengo ese comportamiento en el último Chrome). - m03geek
Necesitaba hacer esto dentro de un bucle codicioso, comparé esta función VS la que estaba usando hasta ahora _.merge (object, [sources]) from lodash (una especie de lib de subrayado): su función es casi dos veces más rápida gracias amigo. - Arnaud Bouchot
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.
respondido 16 nov., 15:16
20
Para objetos no demasiado complicados, podría 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 ocurrir dentro de una cuerda!
Respondido 28 Oct 17, 13:10
var so1 = JSON.stringify(obj1); var so2 = JSON.stringify(obj1); objMerge = so1.substr(0, so1.length-1)+","+so2.substr(1); console.info(objMerge);
- Quamis
function merge(obj1, obj2) { return JSON.parse((JSON.stringify(obj1) + JSON.stringify(obj2)) .replace(/\}\{/g, ',').replace(/,\}/g, '}').replace(/\{,/g, '{')); }
- Alex Ivasyuv
o como una sola línea: objMerge = JSON.parse((JSON.stringify(obj1) + JSON.stringify(obj2)).replace(/\}\{/, ", "));
- Rabino Shuki Gur
@Charles, lo siento, pero ¿cómo es "este método muy peligroso" pero también divertido? Este es el más seguro posible. En primer lugar, utiliza JSON para hacer el trabajo pesado de leer el contenido del objeto. En segundo lugar, utiliza el objeto JSON, que es, por supuesto, el más seguro. máquina optimizada para analizar JSO desde un literal de cadena de objeto compatible con JSON. Y también es compatible con versiones anteriores de IE1, que es el primer navegador en implementar su estándar. Simplemente me hace preguntarme "¿por qué, oh, por qué tuviste que decir una cosa tan estúpida y salirte con la tuya"? - bekim bacaj
Creo que las funciones en el objeto se descompondrán aquí ya que no se puede usar stringify, pero ¿podemos aclarar otras desventajas? - sídixon
17
La mejor manera de hacerlo es agregar una propiedad adecuada que no se pueda enumerar 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.
Espero que esto ayude:
Object.defineProperty (Object.prototype, "extender", {enumerable: false, value: function (from) {var props = Object.getOwnPropertyNames (from); var dest = this; props.forEach (function (name) {if ( nombre en dest) {var destino = Object.getOwnPropertyDescriptor (de, nombre); Object.defineProperty (dest, nombre, destino);}}); devuelve esto;}});
Una vez que tenga eso funcionando, puede hacer:
var obj = {nombre: 'pila', fin: 'desbordamiento'} var reemplazo = {nombre: 'stock'}; obj.extend (reemplazo);
Acabo de escribir una publicación de blog sobre esto aquí: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
respondido 09 nov., 10:22
Espere un segundo --- ¡el código no funciona! :( lo insertó en jsperf para compararlo con otros algoritmos de fusión, y el código falla - la función extender no existe - Jens roland
16
Simplemente puede usar jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Actualmente obj1
contiene todos los valores de obj1
y obj2
respondido 01 mar '16, 10:03
14
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.
Respondido 25 Oct 16, 21:10
¿Te refieres a Object.prototype.extend? En cualquier caso, no es una buena idea extender Object.prototype. -1. - SoluciónYogi
Ahora que lo pienso, probablemente debería ser Object.prototype
y no Object
... Buena idea o no, esto es lo que prototype.js
framework lo hace, por lo que si lo está utilizando u otro framework que dependa de él, Object.prototype
ya se extenderá con extend
. - efímero
No quiero insistir en ti, pero decir que está bien porque prototype.js lo hace es un mal argumento. Prototype.js es popular, pero no significa que sean el modelo a seguir sobre cómo hacer JavaScript. Consulte esta revisión detallada de la biblioteca de prototipos realizada por un profesional de JS. dhtmlkitchen.com/?category=/JavaScript/&date=2008/06/17/… - SoluciónYogi
¿A quién le importa si está bien o mal? Si funciona, entonces funciona. Esperar la solución perfecta es genial, excepto cuando se trata de mantener un contrato, ganar nuevos clientes o cumplir con los plazos. Dale dinero gratis a cualquiera que sea un apasionado de la programación y eventualmente hará todo de la manera "correcta". - David
¿Dónde encontraron todos ustedes? Object.prototype
? Object.extend
no interferirá con sus objetos, simplemente adjunta una función a un Object
objeto. Y obj1.extend(obj2)
no es la forma correcta de disparar la función, utilice Object.extend(obj1, obj2)
en lugar de - artnikpro
13
** Fusionar objetos es simple usando Object.assign
o la propagación ...
operador **
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.car
anula obj1.car
Respondido 30 ago 19, 12:08
12
Solo si alguien esta usando Biblioteca de cierre de Google:
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'
Respondido 25 Oct 16, 22:10
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 anteriores - hay muchas otras respuestas que abordan ES6.
No vi ninguno "profundo" fusión de objetos utilizando el arguments
propiedad. Aquí está mi respuesta: compacto & recursiva, permitiendo que se pasen 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 ...
Respondido 25 ago 20, 18:08
¡La respuesta más corta que funciona muy bien! ¡Se merece más votos a favor! - Jens Tornell
10
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 iguales se puede encontrar aquí: Comparación de objetos en JavaScript
contestado el 23 de mayo de 17 a las 13:05
10
In MooToolshay Object.merge ():
Object.merge(obj1, obj2);
Respondido 25 Oct 16, 21:10
9
In 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)
Respondido 25 Oct 16, 21:10
Tenga cuidado con el error EXTJS-9173 en EXT.Object.merge aún después de +2 años aún no resuelto - Chris
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"}
Respondido el 18 de Septiembre de 18 a las 02:09
7
Basado en Markus y vsync 'respuesta, esta es una versión ampliada. La función acepta cualquier número de argumentos. Se puede utilizar para establecer propiedades en DOM nodos y realiza copias profundas de 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.
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;
}
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;
}
respondido 06 nov., 17:21
5
Deberías usar lodash's predeterminados profundos
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
Respondido el 22 de diciembre de 15 a las 11:12
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}
Respondido 25 Oct 16, 22:10
5
let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);
Respondido el 17 de enero de 19 a las 11:01
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas javascript javascript-objects or haz tu propia pregunta.
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
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 y el valor en obj1 se elimina. Por ejemplo, si el ejemplo de la pregunta hubiera
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 tienes valores que sonarrays
, luego use la opción "arrayMerge" de github "TehShrike / deepmerge", como se mencionó aquí. - ToolmakerSteveSiga el enlace a continuación stackoverflow.com/questions/171251/… El operador de propagación que es la nueva característica en la versión ES6 - Soura Sankar Ghosh