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

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

obj1.merge(obj2);

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

是否有一种内置的方法来实现这一点?我不需要递归,也不需要合并函数,只需要平面对象上的方法。


当前回答

最好的方法是使用Object.defineProperty添加一个不可枚举的适当属性。

通过这种方式,您仍然可以迭代对象财产,而无需使用Object.prototype.extend创建属性时新创建的“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

其他回答

ECMAScript 2018标准方法

您可以使用对象扩散:

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

merged现在是obj1和obj2的并集。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/plugin提议对象rest spread插件才能工作(该插件包含在ES2018中的@babel/preset-env中)。

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

对象.assign()

ECMAScript 2015(ES6)

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

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.

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

您可以简单地使用jQuery扩展

var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };

jQuery.extend(obj1, obj2);

现在obj1包含obj1和obj2的所有值

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

它应该使用对象或实例化函数。

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

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 mammal
john.merge(new Mammal());
john.say();

// Extend mammal and override from mammal
john.merge(new Mammal(), true);
john.say();