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

  显示原文与译文双语对照的内容

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


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

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

任何人都有这个脚本的脚本,或者知道如何做这个? 我不需要递归,也不需要合并函数,只需要平面对象上的方法。

时间:


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

注意,这将简单地将 obj2的所有属性添加到 obj1,这可能不是你想要使用未修改的obj1

cases,于 99%相关,如果你使用的是框架,双骰子在你所有的Prototype,那么你已经可以使用检查 hasOwnProperty,但是这段代码,会得到更美观的工作

示例函数:


/**
 * 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文档:


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


的编辑: ( 基于 @webmat)的评论)

上面的代码将改变名为 settings的对象。

如果要创建一个新对象而不修改任何参数,请使用以下命令:


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"}
//defaults and options variable 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 } } };

Altough这是一个古老的问题,我认为应该注意 underscore.jsextend -method在one-liner中执行的操作:


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

类似于 JQuery extend(),,你在 Angular JS中有相同的函数


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

我今天需要合并对象,这个问题( 和答案) 帮助了我很多。 我尝试了一些答案,但没有一个符合我的需求,所以我组合了一些答案,添加了一些内容,并提出了一个新的合并函数。 这就是:


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

中给定的解决方案应加以修改,以检查 source.hasOwnProperty(property)for..in 循环赋值前- 否则,你最终会复制整个Prototype链的属性,这很少是需要的- -

最好的方法是添加一个正确的属性,它是non-enumerable使用 Object.defineProperty 。

通过这种方式,你仍然可以遍历对象的属性,而不用创建新创建的"扩展",如果你想用 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

prototype.js 有:


Object.extend = function(destination,source) {
 for (var property in source)
 destination[property] = source[property];
 return destination;
}

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

如果有人正在使用谷歌关闭库: http://closure-library.googlecode.com/svn/docs/closure_goog_object_object.js.html


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

数组的helper 函数类似: http://closure-library.googlecode.com/svn/docs/closure_goog_array_array.js.html


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

...