如何动态合并两个JavaScript对象的属性?

我需要能够在运行时合并两个(非常简单)JavaScript对象。例如,我想:

var obj1 = { food: 'pizza', car: 'ford' }var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal

有内置的方法来做到这一点吗?我不需要递归,也不需要合并函数,只需平面对象上的方法。

1815266 次浏览

ECMAScript 2018标准方法

你可以使用目标传播

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

merged现在是obj1obj2的并集。obj2中的属性将覆盖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};

这也是此语法的MDN留档。如果您使用的是Babel,您需要Babel-插件-转换-对象-休息-传播插件才能正常工作。

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

(见MDN JavaScript参考


ES5及更早版本的方法

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

请注意,这将简单地将obj2的所有属性添加到obj1,如果您仍然想使用未修改的obj1,这可能不是您想要的。

如果您使用的框架在您的原型上到处都是垃圾,那么您必须使用像hasOwnProperty这样的检查来获得更好的效果,但该代码将适用于99%的情况。

示例函数:

/*** 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.extend = function(destination,source) {for (var property in source)destination[property] = source[property];return destination;}

obj1.extend(obj2)会做你想做的事。

jQuery也有一个实用程序:http://api.jquery.com/jQuery.extend/

摘自jQuery留档:

// Merge options object into settings objectvar 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" }

上面的代码将改变名为#0现有对象


如果您想在不修改任何一个参数的情况下创建新对象,请使用:

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.

我在谷歌上搜索了合并对象属性的代码,并在这里结束。然而,由于没有任何递归合并代码,我自己编写了它。(也许jQuery扩展是递归的?)无论如何,希望其他人也会发现它很有用。

(现在代码不使用Object.prototype:)

代码

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

一个例子

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像

o3 = {  a : 10,b : 2,c : {ca : 10,cb : 20,cc : {cca : 101,ccb : 202 } } };

在分配之前,应该修改给定的解决方案以检查for..in循环中的source.hasOwnProperty(property)-否则,您最终会复制整个原型链的属性,这是很少需要的…

原型中的正确实现应该如下所示:

var obj1 = {food: 'pizza', car: 'ford'}var obj2 = {animal: 'dog'}
obj1 = Object.extend(obj1, obj2);

MooTools中,有Object.merge()

Object.merge(obj1, obj2);

对于不太复杂的对象,您可以使用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_/

请注意,在这个例子中,字符串中 "}{" 不能发生

执行此操作的最佳方法是使用Object.define属性添加一个不可枚举的正确属性。

通过这种方式,您仍然可以迭代对象属性,而无需新创建的“扩展”,如果您要使用Object.prototype.extend.创建属性,您将获得这些“扩展”

希望这有助于:

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

一旦你开始工作,你可以做:

var obj = {name: 'stack',finish: 'overflow'}var replacement = {name: 'stock'};
obj.extend(replacement);

我刚刚在这里写了一篇关于它的博客文章:http://onemoredigit.com/post/1527191998/extending-objects-in-node-js

我扩展了David Coallier的方法:

  • 添加了合并多个对象的可能性
  • 支持深度对象
  • 覆盖参数(如果最后一个参数是布尔值,则检测到)

如果覆盖为false,则不会覆盖任何属性,但会添加新属性。

用法:obj.merge(合并…[,覆盖]);

这是我的代码:

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;
// nestingif ((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 propertieselse if ((name in dest && override) || !(name in dest)) {descriptor = Object.getOwnPropertyDescriptor(from, name);if (descriptor.configurable) {Object.defineProperty(dest, name, descriptor);}}});}}return this;}});

示例和测试用例:

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

我的equals方法可以在这里找到:JavaScript中的对象比较

我有点开始使用JavaScript,所以如果我错了请纠正我。

但是,如果您可以合并任意数量的对象,那不是更好吗?这是我使用本机Arguments对象的方法。

关键是您实际上可以将任意数量的参数传递给JavaScript函数,而无需在函数声明中定义它们。如果不使用Arguments对象,您就无法访问它们。

function mergeObjects() (var tmpObj = {};
for(var o in arguments) {for(var m in arguments[o]) {tmpObj[m] = arguments[o][m];}}return tmpObj;}

用途:

//Takes any number of objects and returns one merged objectvar 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;}

它经过测试:

console.log(objectMerge({a:1, b:2}, {a:2, c:4}));

其结果是:

{ a: 2, b: 2, c: 4 }

ExtJS 4中,可以这样做:

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

合并(对象):对象

戈西对大卫·科利尔方法的扩展:

检查这两行:

from = arguments[i];Object.getOwnPropertyNames(from).forEach(function (name) {

需要检查“from”与null对象……如果例如合并来自Ajax响应的对象,之前在服务器上创建的,对象属性可以具有“null”的值,在这种情况下,上面的代码会生成一个错误:

“from”不是一个有效的对象

例如,用if(from!=null){…}包装“…Object.getOwnProperties tyNames(from). for每个…”函数将防止该错误发生。

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 ofor( 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])}elsea[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 )

我今天需要合并对象,这个问题(和答案)对我帮助很大。我尝试了一些答案,但没有一个符合我的需求,所以我结合了一些答案,自己添加了一些东西,想出了一个新的合并函数。它是:

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

一些示例用法:

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

基于马库斯vsync的答案,这是一个扩展版本。该函数接受任意数量的参数。它可用于在DOM节点上设置属性并制作值的深度副本。但是,第一个参数是通过引用给出的。

要检测DOM节点,请使用isDOMNode()函数(请参阅Stack Overflow问题JavaScript isDOM-如何检查JavaScript对象是否为DOM对象?

它在Opera 11,Firefox 6,Internet Explorer 8和GoogleChrome16中进行了测试。

代码

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

一些例子

设置超文本标记语言元素的innerHTML和样式

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

合并数组和对象。请注意,未定义可用于保留左侧数组/对象中的值。

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对象的参数(包括null)都将被忽略。除了第一个参数,DOM节点也被丢弃。注意,像new String()一样创建的字符串实际上是对象。

o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));// o = {0:'d', 1:'e', 2:3, a:'a'}

如果你想将两个对象合并到一个新的(不影响两个对象中的任何一个)中,请提供{}作为第一个参数

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

编辑(订阅关于REAPERSON的评论)

合并数组

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

YUI#0中应该完成工作:

Y.merge(obj1, obj2, obj3....)

请注意,#0#1-方法在一行中这样做:

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

如果有人在使用谷歌关闭库

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

数组存在类似的辅助函数

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'
function extend(){var o = {};
for (var i in arguments){var s = arguments[i];
for (var i in s){o[i] = s[i];}}
return o;}

顺便说一下,你们所做的是覆盖属性,而不是合并…

这就是JavaScript对象区域真正合并的方式:只有to对象中不是对象本身的键才会被from覆盖。其他所有内容都将是真的合并了。当然,您可以更改此行为以不覆盖仅存在于to[n] is undefined等情况下的任何内容…:

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

用法:

var merged = realMerge(obj1, obj2);

这将obj合并为“默认”defobj优先于两者中存在的任何内容,因为obj被复制到def中。还要注意这是递归的。

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

值得一提的是,140byt.es收藏的版本是在最小的空间内解决任务,值得一试:

代码:

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

用于您的目的:

m(obj1,obj2);

这里是原始Gist

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:函数()}

这是我的刺

  1. 支持深度合并
  2. 不改变参数
  3. 接受任意数量的参数
  4. 不扩展对象原型
  5. 不依赖于另一个库(jQueryMooToolsUnderscore.js等)
  6. 包括检查hasOwnProperty
  7. 很短:)

    /*Recursively merge properties and return new objectobj1 &lt;- obj2 [ &lt;- ... ]*/function merge () {var dst = {},src,p,args = [].splice.call(arguments, 0);
    while (args.length > 0) {src = args.splice(0, 1)[0];if (toString.call(src) == '[object Object]') {for (p in src) {if (src.hasOwnProperty(p)) {if (toString.call(src[p]) == '[object Object]') {dst[p] = merge(dst[p] || {}, src[p]);} else {dst[p] = src[p];}}}}}
    return dst;}

Example:

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

您可以为每个对象分配一个默认合并(也许“继承”一个更好的名称)方法:

它应该与对象或实例化函数一起工作。

如果需要,下面的代码会处理重写合并的值:

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

测试数据如下:

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 mammaljohn.merge(new Mammal());john.say();
// Extend mammal and override from mammaljohn.merge(new Mammal(), true);john.say();

我的方式:

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

:)

我已经使用Object.create()来保持默认设置(使用__proto__或Object.get原型())。

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()'或'ush()'。

var newArray = options['keyName'].concat( options.__proto__['keyName'] );

说明:您需要在连接之前进行hasOwnProperty检查以避免重复。

与jQuery扩展()类似,您在AngularJS中具有相同的函数:

// Merge the 'options' object into the 'settings' objectvar settings = {validate: false, limit: 5, name: "foo"};var options  = {validate: true, name: "bar"};angular.extend(settings, options);

使用Underscore.js,要合并对象数组,请执行以下操作:

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

其结果是:

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

对于那些使用Node.js的人,有一个NPM模块:node.extend

安装:

npm install node.extend

用法:

var extend = require('node.extend');var destObject = extend(true, {}, sourceObject);// Where sourceObject is the object whose properties will be copied into another.

github上有一个名为#0的库:这似乎得到了一些牵引力。它是一个独立的,可以通过npm和b伤脑筋的包管理器获得。

我倾向于使用或改进这一点,而不是从答案中复制粘贴代码。

和谐ECMAScript 2015(ES6)指定#0将执行此操作。

Object.assign(obj1, obj2);

当前的浏览器支持是变得更好,但如果您正在为不支持的浏览器开发,您可以使用聚填充

此解决方案创建新对象并能够处理多个对象

此外,它是递归,你可以选择天气你想要覆盖值对象

    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的内容:

{"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/

以下两个可能是一个很好的起点。Lodash还为那些特殊需求提供了定制功能!

_.extendhttp://underscorejs.org/#extend
_.mergehttps://lodash.com/docs#merge

另一种方法:

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

我使用纯JavaScript中的以下内容。它从最右边的参数开始,一直组合到第一个参数。没有返回值,只有第一个参数被修改,最左边的参数(除了第一个)对属性的权重最高。

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

您可以简单地使用jQuery#0

var obj1 = { val1: false, limit: 5, name: "foo" };var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);

现在obj1包含obj1obj2的所有值

如果您使用的是Dojo工具包,那么合并两个对象的最佳方法是使用混合。

下面是Dojo Toolkit混合的示例:

// 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.7var a = { b:"c", d:"e" };dojo.mixin(a, { d:"f", g:"h" });console.log(a); // b:c, d:f, g:h

有关详细信息,请混合

你可以按照我的方法合并对象

var obj1 = { food: 'pizza', car: 'ford' };var obj2 = { animal: 'dog' };
var result = mergeObjects([obj1, obj2]);
console.log(result);document.write("result: <pre>" + JSON.stringify(result, 0, 3) + "</pre>");
function mergeObjects(objectArray) {if (objectArray.length) {var b = "", i = -1;while (objectArray[++i]) {var str = JSON.stringify(objectArray[i]);b += str.slice(1, str.length - 1);if (objectArray[i + 1]) b += ",";}return JSON.parse("{" + b + "}");}return {};}

Object.assign()

ECMAScript 2015(ES6)

这是一项新技术,是ECMAScript 2015(ES6)标准的一部分。该技术的规范已最终确定,但请检查兼容性表以了解各种浏览器中的使用和实现状态。

Object.assign()方法用于将一个或多个源对象中所有可枚举自身属性的值复制到目标对象。它将返回目标对象。

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.

在一行代码中合并N个对象的属性

Object.assign方法是ECMAScript 2015(ES6)标准的一部分,完全符合您的需要。(不支持IE

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

Object.assign()方法用于将所有可枚举自身属性的值从一个或多个源对象复制到目标对象。

阅读更多…

聚填充支持旧浏览器:

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

你应该用Lodash的默认深度

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

实现这一目标的可能方法如下。

if (!Object.prototype.merge){Object.prototype.merge = function(obj){var self = this;Object.keys(obj).forEach(function(key){self[key] = obj[key]});}};

我不知道它是否比其他答案更好。在这个方法中,您将merge function添加到Objects原型。这样您就可以调用obj1.merge(obj2);

注意:您应该验证您的参数以查看它是否是一个对象并“抛出”一个正确的Error。如果不是Object.keys将“抛出”一个“错误”

这是我在代码库中使用的合并。

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

如果你需要一个深度合并,它也会通过在结果中连接数组来“合并”数组,那么这个ES6函数可能就是你需要的:

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/arrayif (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 objectvar keys = new Set([...Object.keys(a),...Object.keys(b)]);// Recurse and assign to new objectreturn 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);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Note that if only one argument is passed to this function, it acts as a deep clone function.

您可以使用对象扩展语法来实现这一点。它是ES2018及以后的一部分。

const obj1 = { food: 'pizza', car: 'ford' };const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };console.log(obj3);

您可以在EcmaScript2016中执行以下操作

更正:这是第三阶段的提议,但它一直对我有效

const objA = {attrA: 'hello',attrB: true}
const objB = {attrC: 2}
const mergedObj = {...objA, ...objB}

JSON兼容JavaScript对象的合并

我鼓励使用和利用不修改原始源代码的非破坏性方法,“Object.assign”是一个破坏性方法,它也碰巧不是那么生产友好,因为它停止在早期浏览器上工作,你没有办法用替代方案干净地修补它。

无论解决方案如何,合并JS对象总是遥不可及或不完整。但是合并符合JSON的兼容对象距离能够编写一段简单且可移植的代码仅一步之遥,这种代码是将一系列JS对象合并到返回的主对象中的非破坏性方法,该方法包含所有唯一的属性名称及其相应的值,这些值出于预期目的合成在单个主对象中。

考虑到MSIE8是第一个为JSON对象添加本机支持的浏览器,这是一个很大的解脱,重用已经存在的技术总是一个受欢迎的机会。

将你的代码限制为JSON补充标准对象,与其说是一种限制,不如说是一种优势-因为这些对象也可以通过Internet传输。当然,对于那些想要更深层次的向后兼容性的人来说,总是有一个json插件,其方法可以很容易地分配给外部代码中的JSON变量,而无需修改或重写正在使用的方法。

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() +"}" );}

(当然,人们总是可以给它一个更有意义的名字,我还没有决定;应该将其命名为JSON合并)

用例:

var master = Merge( obj1, obj2, obj3, ...objn );

现在,与Object.assign相反,这会使所有对象保持不变并处于原始状态(如果您做错了什么,需要重新排序合并对象或能够在再次合并它们之前将它们单独用于其他操作)。

Merge参数的数量也被参数长度限制只有[这是巨大的]。原生支持的JSON parse/stringify已经进行了机器优化,这意味着:它应该比任何脚本形式的JS循环更快。给定参数的迭代是使用while完成的-被证明是JS中最快的循环。

简单地提一下我们已经知道的事实,即唯一对象标签(键)的重复属性将被包含相同键标签的后一个对象覆盖,这意味着您可以通过简单地排序或重新排序参数列表来控制哪个属性接管前一个属性。以及获得一个干净和更新的主对象的好处,没有重复作为最终输出。

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

ES5兼容原生单行:

var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})

**使用Object.assign或传播...运算符合并对象很简单**

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

对象从右向左合并,这意味着与右侧对象具有相同属性的对象将被覆盖。

在这个例子中,obj2.car覆盖了obj1.car

哇…这是我看到的第一个有多页的StackOverflow帖子。抱歉添加了另一个“答案”


ES5及更早版本

此方法适用于ES5及更早版本-有很多其他解决ES6的答案。

我没有看到任何“深”对象使用#0属性合并。这是我的答案-紧凑递归,允许传递无限对象参数:

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

示例

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


这个答案现在只是沧海一粟…

我们可以crate一个空对象,并通过for-loop组合它们:

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)

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

使用jQuery.extend()-Link

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

使用_。-Link

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

使用_扩展()-Link

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

使用Object.assign()ECMAScript 2015(ES6)-Link

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

所有国家的产出

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

使用以下帮助程序,您可以将两个对象合并为一个新对象:

function extend(obj, src) {for (var key in src) {if (src.hasOwnProperty(key)) obj[key] = src[key];}return obj;}
// examplevar a = { foo: true }, b = { bar: false };var c = extend(a, b);
console.log(c);// { foo: true, bar: false }

当将选项字典与函数或插件中的默认设置合并时,这通常很有用。

如果不需要支持IE 8,您可以使用Object.keys来代替相同的功能:

function extend(obj, src) {Object.keys(src).forEach(function(key) { obj[key] = src[key]; });return obj;}

这涉及更少的代码并且更快。

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

ES2018/TypeScript:许多答案都可以,但当您需要合并两个对象不覆盖重叠对象键时,我想出了一个更优雅的解决方案来解决这个问题。

我的函数也接受无限数量的物体作为函数参数合并:

(我在这里使用TypeScript符号,如果您使用的是纯JavaScript,请随时删除函数参数中的:object[]类型)。

const merge = (...objects: object[]) => {return objects.reduce((prev, next) => {Object.keys(prev).forEach(key => {next[key] = { ...next[key], ...prev[key] }})return next})}

使用Object.assign扩展运算符合并两个对象。

错误的方式(修改原始对象,因为目标是o1)

var o1 = { X: 10 };var o2 = { Y: 20 };var o3 = { Z: 30 };var merge = Object.assign(o1, o2, o3);console.log(merge)  // {X:10, Y:20, Z:30}console.log(o1)     // {X:10, Y:20, Z:30}

正确的方式

  • Object.assign({}, o1, o2, o3)==>瞄准新对象

  • {… o1,… o2,… o3}==>扩展对象

var o1 = { X: 10 };var o2 = { Y: 20 };var o3 = { Z: 30 };
console.log('Does not modify original objects because target {}');var merge = Object.assign({}, o1, o2, o3);console.log(merge); // { X: 10, Y: 20, Z: 30 }console.log(o1)
console.log('Does not modify original objects')var spreadMerge = {...o1, ...o2, ...o3};console.log(spreadMerge);console.log(o1);

似乎这应该是所有你需要的:

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

之后,Objectiv3现在应该具有以下值:

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

试试这里:

var obj1 = { food: 'pizza', car: 'ford' }var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
console.log(obj3);

var obj = { name : "Jacob" , address : ["America"] }var obj2 = { name : "Shaun" , address : ["Honk Kong"] }
var merged = Object.assign({} , obj,obj2 ); //shallow mergeobj2.address[0] = "new city"

result.address[0]改为“新城市”,即合并对象也发生了变化。这就是浅合并的问题。

var obj = { name : "Jacob" , address : ["America"] }var obj2 = { name : "Shaun" , address : ["Honk Kong"] }
var result = Object.assign({} , JSON.parse(JSON.stringify(obj)),JSON.parse(JSON.stringify(obj2)) )
obj2.address[0] = "new city"

result.address[0]不变

您可以使用Object.assign方法。例如:

var result = Object.assign(obj1, obj2);

另外,请注意,它创建了对象的浅表副本。

使用遵循ES6版本的传播运算符

var obj1 = { food: 'pizza', car: 'ford' }var obj2 = { animal: 'dog' }let result = {...obj1,...obj2};console.log(result)
output { food: 'pizza', car: 'ford', animal: 'dog' }

有不同的方法来实现这一点:

Object.assign(targetObj, sourceObj);
targetObj = {...targetObj, ...sourceObj};
Object.assign(TargetObject, Obj1, Obj2, ...);

有三种方法可以做到这一点:

办法1:

// using spread ...let obj1 = {...obj2};

方法2:-

// using  Object.assign() methodlet obj1 = Object.assign({}, obj2);

方法3:-

// using JSONlet obj1 = JSON.parse(JSON.stringify(obj2));

使用jQuery库尝试这种方式

let obj1 = { food: 'pizza', car: 'ford' }let obj2 = { animal: 'dog' }
console.log(jQuery.extend(obj1, obj2))

用这个

var t=merge({test:123},{mysecondTest:{blub:{test2:'string'},args:{'test':2}}})console.log(t);
function merge(...args) {return Object.assign({}, ...args);}

var firstObject = {key1 : 'value1',key2 : 'value2'};
var secondObject={...firstObject,key3 : 'value3',key4 : 'value4',key5 : 'value5'}console.log(firstObject);console.log(secondObject);