recorrer - ¿Cómo puedo combinar dinámicamente las propiedades de dos objetos JavaScript?
recorrer objeto json javascript (30)
Fusionar propiedades de N objetos en una línea de código
Un método Object.assign
es parte del estándar ECMAScript 2015 (ES6) y hace exactamente lo que necesita. ( IE
no es compatible)
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 soportar 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;
}
});
}
Necesito poder combinar 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 forma integrada para hacer esto? No necesito recursión, y no necesito combinar funciones, solo métodos en objetos planos.
Aquí está mi puñalada que
- Soporta fusión profunda
- No muta argumentos
- Toma cualquier cantidad de argumentos
- No extiende el objeto prototipo.
- 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
};
*/
Busqué en Google el código para combinar las propiedades del objeto y terminé aquí. Sin embargo, como no había ningún código para la combinación recursiva, lo escribí yo mismo. (¿Quizás jQuery extend sea recursivo por cierto?) De todos modos, espero que alguien más también lo encuentre útil.
(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 objeto o3 como
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Extendí el método de David Coallier:
- Añadida la posibilidad de fusionar múltiples objetos.
- Soporta objetos profundos
- parámetro de anulación (que se detecta si el último parámetro es booleano)
Si la anulación es falsa, ninguna propiedad se anula, 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 TestCases:
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]));
El método de mis iguales se puede encontrar aquí: Comparación de objetos en JavaScript
La mejor manera de hacer esto es agregar una propiedad adecuada que no sea enumerable usando Object.defineProperty.
De esta manera, aún podrá iterar sobre las propiedades de los objetos sin tener la "extensión" recién creada que obtendría si creara la propiedad con Object.prototype.extend.
Esperemos que 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 tienes que trabajar, puedes hacer:
var obj = { name: ''stack'', finish: ''overflow'' } var replacement = { name: ''stock'' }; obj.extend(replacement);
Acabo de escribir una entrada de blog al respecto aquí: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
Las soluciones dadas deben modificarse para verificar source.hasOwnProperty(property)
en los bucles for..in
antes de asignar; de lo contrario, terminará copiando las propiedades de toda la cadena del prototipo, que rara vez se desea ...
Los dos siguientes son probablemente un buen punto de partida. lodash también tiene una función de personalizador para esas necesidades especiales!
_.extend
( underscorejs.org/#extend )
_.merge
( https://lodash.com/docs#merge )
Necesito fusionar objetos hoy, y esta pregunta (y respuestas) me ayudó mucho. Probé algunas de las respuestas, pero ninguna de ellas se ajustó a mis necesidades, así que combiné algunas de las respuestas, agregué algo por mi cuenta 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 }));
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!
Por cierto, lo que está haciendo es sobrescribir las propiedades, no fusionar ...
Así es como el área de objetos de JavaScript realmente se fusionó: solo se sobrescribirán las claves en el objeto a que no sean objetos en sí. Todo lo demás será realmente fusionado . Por supuesto, puede cambiar este comportamiento para no sobrescribir nada de lo que existe, como 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);
Puede utilizar las propiedades de dispersión de objetos, actualmente una propuesta de ECMAScript de la etapa 3.
const obj1 = { food: ''pizza'', car: ''ford'' };
const obj2 = { animal: ''dog'' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
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);
Simplemente puedes usar jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Ahora obj1
contiene todos los valores de obj1
y obj2
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''
Tenga en cuenta que underscorejs.org/#extend hace esto en una sola línea:
_.extend({name : ''moe''}, {age : 50});
=> {name : ''moe'', age : 50}
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 denominado 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.
Prototype tiene esto:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2)
hará lo que quieras.
Harmony ECMAScript 2015 (ES6) especifica developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… que hará 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 .
Fusionar objetos es 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);
Los objetos se combinan 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
Método estándar ECMAScript 2018
Usaría la propagación de objetos :
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 MDN )
Método para ES5 y 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 usar el obj1
no modificado.
Si está utilizando un marco que cubre todos sus prototipos, entonces tiene que ser más sofisticado 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;
}
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 verifique la tabla de compatibilidad para el uso y el estado de 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. Se 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.
Basado en la respuesta de Markus'' y vsync , esta es una versión ampliada. La función toma cualquier número de argumentos. Se puede usar para establecer propiedades en los nodos DOM y hacer copias en profundidad 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 sobre el desbordamiento de pila JavaScript isDOM - ¿Cómo verifica 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 usar para preservar 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''}
Cualquier argumento que no sea un objeto JavaScript (incluido el valor nulo) se ignorará. Excepto por el primer argumento, también se descartan los nodos DOM. Tenga en cuenta que es decir, las cadenas creadas como nuevas String () son en realidad 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 combinar dos objetos en un nuevo (sin afectar a ninguno de los dos), suministre {} 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):
También fusionar 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;
}
Con Underscore.js , para fusionar una matriz de objetos haz:
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}
Deberías usar los defaultsDeep por defaultsDeep de lodashDeepdefaultsDeep
_.defaultsDeep({ ''user'': { ''name'': ''barney'' } }, { ''user'': { ''name'': ''fred'', ''age'': 36 } });
// → { ''user'': { ''name'': ''barney'', ''age'': 36 } }
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)
En MooTools , hay Object.merge() :
Object.merge(obj1, obj2);
Vale la pena mencionar que la versión de la colección 140byt.es está resolviendo la tarea en un espacio mínimo y vale la pena intentarlo con este propósito:
Código:
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])}
Uso para su propósito:
m(obj1,obj2);
Aquí está la Gist original .
Wow ... esta es la primera publicación de que he visto con varias páginas. Disculpas por agregar otra "respuesta"
Este método es para ES5 y versiones anteriores : hay muchas otras respuestas relacionadas con ES6.
No vi ningún objeto "profundo" fusionándose utilizando la arguments
propiedad. 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++) {
// 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 parte que se comenta es opcional ... simplemente saltará los argumentos pasados que no sean objetos (evitando errores).
Ejemplo:
extend({
api: 1,
params: {
query: ''hello''
}
}, {
params: {
query: ''there''
}
});
// outputs {api: 1, params: {query: ''there''}}
Esta respuesta es ahora una gota en el océano ...
Yo uso lo siguiente que está en JavaScript puro. Comienza desde el argumento más a la derecha y los combina hasta el primer argumento. No hay un valor de retorno, solo se modifica el primer argumento y el parámetro que está más a la izquierda (excepto el primero) tiene el mayor peso en las propiedades.
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];
}
}
}
};