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

...