How can I merge properties of two JavaScript objects dynamically?
我需要能够在运行时合并两个(非常简单)javascript对象。例如,我想:
1 2 3 4 5 6 | var obj1 = { food: 'pizza', car: 'ford' } var obj2 = { animal: 'dog' } obj1.merge(obj2); //obj1 now has three properties: food, car, and animal |
有没有人有这个脚本或者知道一个内置的方法来做这个?我不需要递归,也不需要合并函数,只需要平面对象上的方法。
ECMAScript 2018标准方法
您将使用对象排列:
1 2 3 4 5 | let merged = {...obj1, ...obj2}; /** There's no limit to the number of objects you can merge. * Later properties overwrite earlier properties with the same name. */ const allRules = {...obj1, ...obj2, ...obj3}; |
ECMAScript 2015(ES6)标准方法
1 2 3 4 5 6 7 8 | /* 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); |
(参见MDN javascript参考)
ES5及更早版本的方法
1 | for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; } |
请注意,这只会将EDOCX1的所有属性(0)添加到
如果你使用的框架覆盖了你的原型,那么你必须对像
示例函数:
1 2 3 4 5 6 7 8 9 10 11 12 | /** * 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; } |
jquery还为此提供了一个实用程序:http://api.jquery.com/jquery.extend/。
摘自jquery文档:
1 2 3 4 5 6 7 | // 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" } |
上述代码将改变名为
如果要在不修改任何参数的情况下创建新对象,请使用以下命令:
1 2 3 4 5 6 7 8 9 | 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. |
Harmony EcmaScript 2015(ES6)规定了将要执行此操作的
1 | Object.assign(obj1, obj2); |
当前的浏览器支持越来越好,但是如果您正在为没有支持的浏览器开发,则可以使用polyfill。
我在谷歌上搜索了合并对象属性的代码,结果就出现在这里。但是,由于没有任何用于递归合并的代码,所以我自己编写了它。(也许jquery扩展是递归的btw?)无论如何,希望其他人也能发现它的用处。
(现在代码不使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * 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; } |
一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); |
生成类对象O3
1 2 3 4 5 6 7 8 | o3 = { a : 10, b : 2, c : { ca : 10, cb : 20, cc : { cca : 101, ccb : 202 } } }; |
请注意,
1 2 | _.extend({name : 'moe'}, {age : 50}); => {name : 'moe', age : 50} |
与jquery extend()类似,AngularJS中有相同的函数:
1 2 3 4 | // 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); |
今天我需要合并对象,这个问题(和答案)帮助了我很多。我尝试了一些答案,但没有一个符合我的需要,所以我结合了一些答案,自己添加了一些东西,并提出了一个新的合并函数。这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; }; |
一些示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 })); |
您可以使用对象排列属性,当前是阶段3 ECMAScript建议。
1 2 3 4 5 | const obj1 = { food: 'pizza', car: 'ford' }; const obj2 = { animal: 'dog' }; const obj3 = { ...obj1, ...obj2 }; console.log(obj3); |
在分配之前,应该修改给定的解决方案以检查
在一行代码中合并n个对象的属性
1 | 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.
多读…
支持旧浏览器的polyfill:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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; } }); } |
以下两个可能是一个很好的起点。洛达什也有一个定制功能,为那些特殊的需要!
顺便说一下,您所做的就是覆盖属性,而不是合并…
这就是javascript对象区域真正合并的方式:只有
1 2 3 4 5 6 7 8 9 10 11 12 | 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; }; |
用途:
1 | var merged = realMerge(obj1, obj2); |
这是我的刺
简称:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* 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; } |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 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 }; */ |
赋值()
ECMAScript 2015(ES6)
这是一项新技术,是ECMAScript 2015(ES6)标准的一部分。这项技术的规范已经最终确定,但是在各种浏览器中检查兼容性表的使用和实现状态。
object.assign()方法用于将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
1 2 3 4 5 6 7 | 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. |
对于不太复杂的对象,可以使用JSON:
1 2 3 4 5 6 7 8 9 10 11 12 | 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_/ |
请注意,在本例中,""不能出现在字符串中!
最好的方法是使用object.defineproperty添加一个不可枚举的适当属性。
通过这种方式,您仍然可以迭代对象属性,而不需要使用object.prototype.extend创建新创建的"extend"属性。
希望这有助于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } }); |
一旦你开始工作,你就可以:
1 2 3 4 5 6 7 8 9 | var obj = { name: 'stack', finish: 'overflow' } var replacement = { name: 'stock' }; obj.extend(replacement); |
我刚刚在这里写了一篇关于它的博客:http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
您只需使用jquery
1 2 3 4 | var obj1 = { val1: false, limit: 5, name:"foo" }; var obj2 = { val2: true, name:"bar" }; jQuery.extend(obj1, obj2); |
现在,
Github上有一个叫做
我倾向于在这个问题上使用或改进,而不是从答案中复制粘贴代码。
原型有:
1 2 3 4 5 | Object.extend = function(destination,source) { for (var property in source) destination[property] = source[property]; return destination; } |
如果有人在使用谷歌关闭库:
1 2 3 4 5 | 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}; |
数组存在类似的助手函数:
1 2 3 4 | 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' |
合并对象很简单。
1 2 3 4 5 6 7 8 | 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); |
对象从右到左合并,这意味着将覆盖与右对象具有相同属性的对象。
在本例中,
在moootools中,有object.merge():
1 | Object.merge(obj1, obj2); |
我扩展了大卫·考利埃的方法:
- 添加了合并多个对象的可能性
- 支持深对象
- override参数(如果最后一个参数是布尔值,则检测到该参数)
如果override为false,则不会覆盖任何属性,但将添加新属性。
用途:对象合并(合并…[,超越];
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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; } }); |
示例和测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 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 <hr><P>在Ext JS 4中,可以执行以下操作:</P>[cc lang="javascript"]var mergedObject = Ext.Object.merge(object1, object2) // Or shorter: var mergedObject2 = Ext.merge(object1, object2) |
请参见合并(对象):对象。
基于markus和vsync的答案,这是一个扩展版本。函数接受任意数量的参数。它可以用于在DOM节点上设置属性,并对值进行深度复制。但是,第一个参数是通过引用给出的。
要检测DOM节点,使用is dom node()函数(请参见堆栈溢出问题javascript is dom-如何检查javascript对象是否为DOM对象?)
它在Opera 11、Firefox 6、Internet Explorer 8和Google Chrome 16中进行了测试。
代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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; } |
一些实例
设置HTML元素的innerHTML和样式
1 2 3 4 | mergeRecursive( document.getElementById('mydiv'), {style: {border: '5px solid green', color: 'red'}}, {innerHTML: 'Hello world!'}); |
合并数组和对象。请注意,Undefined可用于在LeftHand数组/对象中预设值。
1 2 | 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'} |
任何不属于javascript对象(包括空)的参数都将被忽略。除了第一个参数外,还将丢弃DOM节点。注意,如new string()创建的字符串实际上是对象。
1 2 | o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de')); // o = {0:'d', 1:'e', 2:3, a:'a'} |
如果要将两个对象合并为一个新对象(不影响其中任何一个),请提供作为第一个参数
1 2 3 | 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 |
编辑(由reapersoon):
同时合并数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; } |
真的。。这是我看到的第一个多页的StackOverflow帖子。为添加另一个"答案"而道歉
此方法适用于ES5和早期版本-有许多其他答案可用于ES6。
我没有看到任何利用
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
注释掉的部分是可选的。它将跳过传递的不是对象的参数(防止错误)。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 | extend({ api: 1, params: { query: 'hello' } }, { params: { query: 'there' } }); // outputs {api: 1, params: {query: 'there'}} |
This answer is now but a drop in the ocean ...
对于underline.js,要合并对象数组,请执行以下操作:
1 2 | var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ]; _(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); }); |
其结果是:
1 | Object {a: 1, b: 2, c: 3, d: 4} |
1 2 3 4 5 | var obj1 = { food: 'pizza', car: 'ford' } var obj2 = { animal: 'dog' } // result result: {food:"pizza", car:"ford", animal:"dog"} |
使用jquery.extend()-link
1 2 | // Merge obj1 & obj2 to result var result1 = $.extend( {}, obj1, obj2 ); |
使用.merge()-链接
1 2 | // Merge obj1 & obj2 to result var result2 = _.merge( {}, obj1, obj2 ); |
使用扩展()-链接
1 2 | // Merge obj1 & obj2 to result var result3 = _.extend( {}, obj1, obj2 ); |
使用object.assign()ecmascript 2015(es6)-link
1 2 | // Merge obj1 & obj2 to result var result4 = Object.assign( {}, obj1, obj2 ); |
全输出
1 2 3 4 5 6 | 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"} |
值得一提的是,来自140byt.es集合的版本正在最小空间内解决该任务,因此值得尝试:
代码:
1 | 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])} |
用途:
1 | m(obj1,obj2); |
这是最初的要点。
你应该使用洛达什的默认深度
1 2 | _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); // → { 'user': { 'name': 'barney', 'age': 36 } } |
我使用纯JavaScript中的以下内容。它从最右边的参数开始,并将它们一直组合到第一个参数。没有返回值,只修改第一个参数,最左边的参数(第一个参数除外)在属性上的权重最高。
1 2 3 4 5 6 7 8 9 10 11 | 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]; } } } }; |
ES2018/typescript:很多答案都可以,但当您需要合并两个对象而不覆盖重叠的对象键时,我已经想出了一个更优雅的解决方案。
我的函数还接受无限数量的对象作为函数参数进行合并:
(我在这里使用的是typescript符号,如果您使用的是纯javascript,请随意删除函数参数中的
1 2 3 4 5 6 7 8 | const merge = (...objects: object[]) => { return objects.reduce((prev, next) => { Object.keys(prev).forEach(key => { next[key] = { ...next[key], ...prev[key] } }) return next }) } |
我的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function mergeObjects(defaults, settings) { Object.keys(defaults).forEach(function(key_default) { if (typeof settings[key_default] =="undefined") { settings[key_default] = defaults[key_default]; } else if (isObject(defaults[key_default]) && isObject(settings[key_default])) { mergeObjects(defaults[key_default], settings[key_default]); } }); function isObject(object) { return Object.prototype.toString.call(object) === '[object Object]'; } return settings; } |
:)
用途:
1 2 3 4 5 6 7 8 9 10 11 12 | //Takes any number of objects and returns one merged object var objectMerge = function(){ var out = {}; if(!arguments.length) return out; for(var i=0; i<arguments.length; i++) { for(var key in arguments[i]){ out[key] = arguments[i][key]; } } return out; } |
试验对象:
1 | console.log(objectMerge({a:1, b:2}, {a:2, c:4})); |
其结果是:
1 | { a: 2, b: 2, c: 4 } |
戈西对大卫·考利埃方法的扩展:
检查这两行:
1 2 | from = arguments[i]; Object.getOwnPropertyNames(from).forEach(function (name) { |
一个需要检查"从"与空对象…例如,如果合并先前在服务器上创建的Ajax响应中的对象,则对象属性的值可以为"null",在这种情况下,上述代码会生成一个错误,说明:
"from" is not a valid object
例如,将"…object.getownprotynames(from).foreach…"函数包装为"if(from!"{NULL){…}"将防止该错误发生。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | function extend(o, o1, o2){ if( !(o instanceof Object) ) o = {}; copy(o, o1); if( o2 ) copy(o, o2) function isObject(obj) { var type = Object.prototype.toString.call(obj); return obj === Object(obj) && type != '[object Array]' && type != '[object Function]'; }; function copy(a,b){ // copy o2 to o for( var key in b ) if( b.hasOwnProperty(key) ){ if( isObject(b[key]) ){ if( !isObject(a[key]) ) a[key] = Object.assign({}, b[key]); else copy(a[key], b[key]) } else a[key] = b[key]; } } return o; }; var o1 = {a:{foo:1}, b:1}, o2 = {a:{bar:2}, b:[1], c:()=>{}}, newMerged = extend({}, o1, o2); console.log( newMerged ) console.log( o1 ) console.log( o2 ) |
在Yui
1 | Y.merge(obj1, obj2, obj3....) |
1 2 3 4 | let obj1 = {a:1, b:2}; let obj2 = {c:3, d:4}; let merged = {...obj1, ...obj2}; console.log(merged); |
原型中的正确实现应该如下所示:
1 2 3 4 | var obj1 = {food: 'pizza', car: 'ford'} var obj2 = {animal: 'dog'} obj1 = Object.extend(obj1, obj2); |
ES5兼容的本机一行程序:
1 | var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {}) |
I'm kind of getting started with JavaScript, so correct me if I'm wrong.
But wouldn't it be better if you could merge any number of objects? Here's how I do it using the native
The key to is that you can actually pass any number of arguments to a JavaScript function without defining them in the function declaration. You just can't access them without using the Arguments object.
1 2 3 4 5 6 7 8 9 10 | function mergeObjects() ( var tmpObj = {}; for(var o in arguments) { for(var m in arguments[o]) { tmpObj[m] = arguments[o][m]; } } return tmpObj; } |
这里是我在代码库中用来合并的代码。
1 2 3 4 5 6 7 8 9 10 11 12 | function merge(to, from) { if (typeof to === 'object' && typeof from === 'object') { for (var pro in from) { if (from.hasOwnProperty(pro)) { to[pro] = from[pro]; } } } else{ throw"Merge function can apply only on object"; } } |
对于那些使用node.js的用户,有一个NPM模块:node.extend
安装:1 | npm install node.extend |
用途:
1 2 3 | var extend = require('node.extend'); var destObject = extend(true, {}, sourceObject); // Where sourceObject is the object whose properties will be copied into another. |
可以通过以下方法合并对象
1 2 3 4 5 6 7 | var obj1 = { food: 'pizza', car: 'ford' }; var obj2 = { animal: 'dog' }; var result = mergeObjects([obj1, obj2]); console.log(result); document.write("result: [cc lang="javascript"]" + JSON.stringify(result, 0, 3) +" |
"";函数合并对象(ObjectArray){if(objectArray.length){变量b=",i=-1;while(对象数组[++i])。{var str=json.stringify(objectArray[i]);b+=str.切片(1,str.长度-1);if(objectArray[i+1])b+=",";}返回json.parse(""+b+"");}返回{};}<代码> < /PRE>
合并JSON兼容的javascript对象
我鼓励使用不修改原始源的非破坏性方法,"object.assign"是一种破坏性方法,而且它也不太适合生产,因为它停止在早期的浏览器上工作,而您没有办法用另一种方法干净地修补它。
无论解决方案是什么,合并JS对象都将永远是遥不可及或不完整的。但是合并符合JSON的兼容对象离能够编写一个简单的、可移植的代码仅仅一步之遥,这是一种无损的方法,将一系列JS对象合并到一个返回的主对象中,该主对象包含为达到预期目的而在单个主对象中合成的所有唯一属性名及其对应值。
记住,MSIE8是第一个为JSON对象添加本地支持的浏览器,这是一个很大的缓解,重用现有技术始终是一个受欢迎的机会。
将代码限制为JSON标准对象比限制更具优势,因为这些对象也可以通过Internet传输。当然,对于那些想要更深层次的向后兼容性的人,总会有一个JSON插件,它的方法可以很容易地分配给外部代码中的JSON变量,而不必修改或重写正在使用的方法。
1 2 3 4 5 | function Merge( ){ var a = [].slice.call( arguments ), i = 0; while( a[i] )a[i] = JSON.stringify( a[i++] ).slice( 1,-1 ); return JSON.parse("{"+ a.join() +"}" ); } |
(当然,你可以给它起一个更有意义的名字,我还没有决定,应该叫它jsonmerge)
用例:
1 | var master = Merge( obj1, obj2, obj3, ...objn ); |
现在,与
合并参数的数量也仅受参数长度限制[这是巨大的]。本机支持的JSON parse/stringify已经进行了机器优化,这意味着:它应该比JS循环的任何脚本形式都快。对给定参数的迭代是使用
简单地说,我们已经知道,唯一对象标签(键)的重复属性将被包含相同键标签的后一个对象覆盖,这意味着您可以通过简单地排序或重新排序参数列表来控制哪个属性将取代前一个属性。以及获得一个干净和更新的主对象的好处,没有重复作为最终输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ; var obj1 = {a:1}, obj2 = {b:2}, obj3 = {c:3} ; function Merge( ){ var a = [].slice.call( arguments ), i = 0; while( a[i] )a[i] = JSON.stringify( a[i++] ).slice( 1,-1 ); return JSON.parse("{"+ a.join() +"}" ); } ; var master = Merge( obj1, obj2, obj3 ) ; console.log( JSON.stringify( master ) ) ; |
使用以下助手,可以将两个对象合并为一个新对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function extend(obj, src) { for (var key in src) { if (src.hasOwnProperty(key)) obj[key] = src[key]; } return obj; } // example var a = { foo: true }, b = { bar: false }; var c = extend(a, b); console.log(c); // { foo: true, bar: false } |
这通常在将选项dict与函数或插件中的默认设置合并时很有用。
如果不需要对IE 8的支持,您可以使用
1 2 3 4 | function extend(obj, src) { Object.keys(src).forEach(function(key) { obj[key] = src[key]; }); return obj; } |
这涉及的代码略少,速度稍快。
另一种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function concat_collection(obj1, obj2) { var i; var arr = new Array(); var len1 = obj1.length; for (i=0; i<len1; i++) { arr.push(obj1[i]); } var len2 = obj2.length; for (i=0; i<len2; i++) { arr.push(obj2[i]); } return arr; } var ELEMENTS = concat_collection(A,B); for(var i = 0; i < ELEMENTS.length; i++) { alert(ELEMENTS[i].value); } |
我们可以用板条箱装一个空物体,然后用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var obj1 = { id: '1', name: 'name' } var obj2 = { c: 'c', d: 'd' } var obj3 = {} for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } console.log( obj1, obj2, obj3) |
可以为每个对象指定默认合并(可能是"inherit"更好的名称)方法:
它应该使用对象或实例化函数。
如果需要,下面的代码处理覆盖合并值:
1 2 3 4 5 6 7 8 9 10 | Object.prototype.merge = function(obj, override) { // Don't override by default for (var key in obj) { var n = obj[key]; var t = this[key]; this[key] = (override && t) ? n : t; }; }; |
测试数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var Mammal = function () { this.eyes = 2; this.thinking_brain = false; this.say = function () { console.log('screaming like a mammal')}; } var Human = function () { this.thinking_brain = true; this.say = function() {console.log('shouting like a human')}; } john = new Human(); // Extend mammal, but do not override from mammal john.merge(new Mammal()); john.say(); // Extend mammal and override from mammal john.merge(new Mammal(), true); john.say(); |
如果您使用的是Dojo工具包,那么合并两个对象的最佳方法是使用mixin。
下面是Dojo工具箱mixin的示例:
1 2 3 4 5 6 7 8 9 10 11 | // Dojo 1.7+ (AMD) require(["dojo/_base/lang"], function(lang){ var a = { b:"c", d:"e" }; lang.mixin(a, { d:"f", g:"h" }); console.log(a); // b:c, d:f, g:h }); // Dojo < 1.7 var a = { b:"c", d:"e" }; dojo.mixin(a, { d:"f", g:"h" }); console.log(a); // b:c, d:f, g:h |
更多详情请与我们联系。
此解决方案创建一个新对象,并能够处理多个对象。
此外,它是递归的,您可以选择要覆盖值和对象的天气。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | function extendObjects() { var newObject = {}; var overwriteValues = false; var overwriteObjects = false; for ( var indexArgument = 0; indexArgument < arguments.length; indexArgument++ ) { if ( typeof arguments[indexArgument] !== 'object' ) { if ( arguments[indexArgument] == 'overwriteValues_True' ) { overwriteValues = true; } else if ( arguments[indexArgument] == 'overwriteValues_False' ) { overwriteValues = false; } else if ( arguments[indexArgument] == 'overwriteObjects_True' ) { overwriteObjects = true; } else if ( arguments[indexArgument] == 'overwriteObjects_False' ) { overwriteObjects = false; } } else { extendObject( arguments[indexArgument], newObject, overwriteValues, overwriteObjects ); } } function extendObject( object, extendedObject, overwriteValues, overwriteObjects ) { for ( var indexObject in object ) { if ( typeof object[indexObject] === 'object' ) { if ( typeof extendedObject[indexObject] ==="undefined" || overwriteObjects ) { extendedObject[indexObject] = object[indexObject]; } extendObject( object[indexObject], extendedObject[indexObject], overwriteValues, overwriteObjects ); } else { if ( typeof extendedObject[indexObject] ==="undefined" || overwriteValues ) { extendedObject[indexObject] = object[indexObject]; } } } return extendedObject; } return newObject; } var object1 = { a : 1, b : 2, testArr : [888, { innArr : 1 }, 777 ], data : { e : 12, c : { lol : 1 }, rofl : { O : 3 } } }; var object2 = { a : 6, b : 9, data : { a : 17, b : 18, e : 13, rofl : { O : 99, copter : { mao : 1 } } }, hexa : { tetra : 66 } }; var object3 = { f : 13, g : 666, a : 333, data : { c : { xD : 45 } }, testArr : [888, { innArr : 3 }, 555 ] }; var newExtendedObject = extendObjects( 'overwriteValues_False', 'overwriteObjects_False', object1, object2, object3 ); |
NewExtendedObject的内容:
1 | {"a":1,"b":2,"testArr":[888,{"innArr":1},777],"data":{"e":12,"c":{"lol":1,"xD":45},"rofl":{"O":3,"copter":{"mao":1}},"a":17,"b":18},"hexa":{"tetra":66},"f":13,"g":666} |
小提琴:http://jsfiddle.net/o0gb2umb/
1 2 3 4 | A={a:1,b:function(){alert(9)}} B={a:2,c:3} A.merge = function(){for(var i in B){A[i]=B[i]}} A.merge() |
结果是:a:2,c:3,b:function()
这将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function mergeObjs(def, obj) { if (typeof obj == 'undefined') { return def; } else if (typeof def == 'undefined') { return obj; } for (var i in obj) { if (obj[i] != null && obj[i].constructor == Object) { def[i] = mergeObjs(def[i], obj[i]); } else { def[i] = obj[i]; } } return def; } a = {x : {y : [123]}} b = {x : {z : 123}} console.log(mergeObjs(a, b)); // {x: {y : [123], z : 123}} |
我已经使用了object.create()来保留默认设置(使用uuu proto或object.getprototypeof())。
1 2 3 4 5 6 7 8 | function myPlugin( settings ){ var defaults = { "keyName": ["string 1","string 2" ] } var options = Object.create( defaults ); for (var key in settings) { options[key] = settings[key]; } } myPlugin( {"keyName": ["string 3","string 4" ] } ); |
这样我以后就可以一直使用"concat()"或"push()"。
1 | var newArray = options['keyName'].concat( options.__proto__['keyName'] ); |
注意:为了避免重复,您需要在连接之前进行一次hasownproperty检查。
实现这一点的一种可能方法是:
1 2 3 4 5 6 7 8 | if (!Object.prototype.merge){ Object.prototype.merge = function(obj){ var self = this; Object.keys(obj).forEach(function(key){ self[key] = obj[key] }); } }; |
我不知道是否比其他答案更好。在这个方法中,您将
注意:你应该验证你的论点,看看它是否是一个对象,然后"抛出"一个合适的
您可以在ecmascript2016中执行以下操作
更正:这是第三阶段的提议,但它一直对我有效
1 2 3 4 5 6 7 8 9 10 | const objA = { attrA: 'hello', attrB: true } const objB = { attrC: 2 } const mergedObj = {...objA, ...objB} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function extend() { var o = {}; for (var i in arguments) { var s = arguments[i]; for (var i in s) { o[i] = s[i]; } } return o; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | [cc lang="javascript"] /** This script can merge two multi dimensional associative array/objects in javascript by comparing given object with its reference and will remove additional given keys, adding missed parameteres and also validating values without overhead. Also it will return the default values if no input presented with re-usable reference! Tested on IE8 and greater. **/ var module = (function(){ //To make our reference variable onchangable, have to put it into a function which is fster and more efficient than"JSON.parse(JSON.stringify(VARIABLE))" var _defs = function(){ return { //string, number and boolean are actually regex based validation keys on input values. a: ["string", 'Defaul value for"a"'], b: ["number", 300], c: ["boolean", true], d: { da: ["boolean", true], db: ["string", 'Defaul value for"db"'], dc: { dca: ["number", 200], dcb: ["string", 'Default value for"dcb"'], dcc: ["number", 500], dcd: ["boolean", true] }, dce: ["string", 'Default value for"dce"'], }, e: ["number", 200], f: ["boolean", 0], g: ["", 'This is an internal extra parameter'] } } var _validation = { number: function (defaultValue, userValue) { if(/^[0-9]+$/.test(userValue)) //Only numbers allowed return userValue; else return defaultValue; }, string: function (defaultValue, userValue) { if(/^[a-zA-Z\s]*$/.test(userValue)) //Only A to Z case insentitive with space aloowed. return userValue; else return defaultValue; }, boolean: function (defaultValue, userValue) { if(typeof userValue === 'boolean') //True or False or 0 ,1 return userValue; else return defaultValue; } } var _uniqueMerge = function(opts, _ref){ for(var key in _ref) if (_ref && _ref[key] && _ref[key].constructor && _ref[key].constructor === Object) _ref[key] = _uniqueMerge((opts ? opts[key] : null ), _ref[key] ); else if(opts && opts.hasOwnProperty(key)) _ref[key] = _validation[_ref[key][0]](_ref[key][1], opts[key]); //or without validation on user enties => ref[key] = obj[key] else _ref[key] = _ref[key][1]; return _ref; } var _get = function(inputs){ return _uniqueMerge(inputs, _defs()); } return { options: function(){ return _get(arguments[0] || null); // for more safety and control on number of input variables! used --> ( arguments[0] || null ) } } })(); //How to use it: input_one = { a :"Hello World", //b : ["number", 400], //User missed this parameter c:"Hi", d : { da : false, db :"Hellow! World", // ! is not allowed dc : { dca : 10, dcb :"My String", dcc:"3thString", dcd : false }, dce:"ANOTHER STRING", }, e: 40, f: true, z: 'x' }; console.log( JSON.stringify( module.options(input_one), null ,2 ) ); //Output: /* { "a":"Hello World", "b": 300, "c": true, "d": { "da": false, "db":"Defaul value for "db"", "dc": { "dca": 10, "dcb":"My String", "dcc": 500, "dcd": false }, "dce":"ANOTHER STRING" }, "e": 40, "f": true, "g":"This is an internal extra parameter" } */ input_two = { a : 32, //b : ["number", 400], //User missed this parameter c:"Hi", d : { da : false, db :"HelloWorld", dc : { dca : 10, dcb :"My String", dcd : false }, dce: 73, } }; console.log( JSON.stringify( module.options(input_two), null ,2 ) ); //output /* { "a":"Defaul value for "a"", "b": 300, "c": true, "d": { "da": false, "db":"HelloWorld", "dc": { "dca": 10, "dcb":"My String", "dcc": 500, "dcd": false }, "dce":"Default value for "dce"" }, "e": 200, "f": 0, "g":"This is an internal extra parameter" } */ //Empty input will return the default values! console.log( JSON.stringify( module.options(), null ,2 ) ); //Output /* { "a":"Defaul value for "a"", "b": 300, "c": true, "d": { "da": true, "db":"Defaul value for "db"", "dc": { "dca": 200, "dcb":"Default value for "dcb"", "dcc": 500, "dcd": true }, "dce":"Default value for "dce"" }, "e": 200, "f": 0, "g":"This is an internal extra parameter" } */ |
< /代码>
如果您需要一个深度合并,通过在结果中连接数组来"合并"数组,那么这个ES6函数可能就是您需要的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | function deepMerge(a, b) { // If neither is an object, return one of them: if (Object(a) !== a && Object(b) !== b) return b || a; // Replace remaining primitive by empty object/array if (Object(a) !== a) a = Array.isArray(b) ? [] : {}; if (Object(b) !== b) b = Array.isArray(a) ? [] : {}; // Treat arrays differently: if (Array.isArray(a) && Array.isArray(b)) { // Merging arrays is interpreted as concatenation of their deep clones: return [...a.map(v => deepMerge(v)), ...b.map(v => deepMerge(v))]; } else { // Get the keys that exist in either object var keys = new Set([...Object.keys(a),...Object.keys(b)]); // Recurse and assign to new object return Object.assign({}, ...Array.from(keys, key => ({ [key]: deepMerge(a[key], b[key]) }) )); } } // Sample data for demo: var a = { groups: [{ group: [{ name: 'John', age: 12 },{ name: 'Mary', age: 20 }], groupName: 'Pair' }], config: { color: 'blue', range: 'far' } }; var b = { groups: [{ group: [{ name: 'Bill', age: 15 }], groupName: 'Loner' }], config: { range: 'close', strength: 'average' } }; var merged = deepMerge(a, b); console.log(merged); |
1 | .as-console-wrapper { max-height: 100% !important; top: 0; } |
注意,如果只有一个参数传递给这个函数,它就充当一个深度克隆函数。
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Object.prototype.assign = Object.assign && function () { var a = []; for (var _i = 0; _i < arguments.length; _i++) { a[_i] = arguments[_i]; } var src = a.slice(1); var target = a[0]; for (var o in src) { if (src.hasOwnProperty(o)) { var keys = Object.keys(src[o]); var _src = src[o]; for (var k in keys) { if (keys.hasOwnProperty(k)) { var _key = keys[k]; target[_key] = _src[_key]; } } } } return target; }; |