简体   繁体   English

合并对象(关联数组)

[英]Merging objects (associative arrays)

What's the best/standard way of merging two associative arrays in JavaScript? 在JavaScript中合并两个关联数组的最佳/标准方法是什么? Does everyone just do it by rolling their own for loop? 每个人都只是通过滚动自己for循环来做到这一点吗?

with jquery you can call $.extend 使用jquery,你可以调用$.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(assoc. arrays are objects in js) (assoc。数组是js中的对象)

look here: http://api.jquery.com/jQuery.extend/ 看这里: http//api.jquery.com/jQuery.extend/


edit: Like rymo suggested, it's better to do it this way: 编辑:像rymo建议的那样,最好这样做:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

As here obj1 (and obj2) remain unchanged. 因为这里obj1(和obj2)保持不变。


edit2: In 2018 the way to do it is via Object.assign : edit2:在2018年,这样做的方法是通过Object.assign

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

If working with ES6 this can be achieved with the Spread Operator : 如果使用ES6,可以使用Spread Operator实现:

const obj3 = { ...obj1, ...obj2 };

Now in 2016 I would say the best/standard way is Object.assign() 现在在2016年我会说最好的/标准的方式是Object.assign()
Pure Javascript. 纯Javascript。 No jQuery is needed. 不需要jQuery。

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

More information, examples and polyfill here: 更多信息,示例和polyfill:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

This is how Prototype does it: 这就是Prototype的作用:

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

called as, for example: 被称为,例如:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

EDIT : added hasOwnProperty() check as correctly pointed out by bucabay in comments 编辑 :添加hasOwnProperty()检查正确由bucabay在评论中指出

Keep it simple... 把事情简单化...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

Underscore also has an extend method: Underscore也有一个扩展方法:

Copy all of the properties in the source objects over to the destination object. 将源对象中的所有属性复制到目标对象。 It's in-order, so the last source will override properties of the same name in previous arguments. 它是有序的,因此最后一个源将覆盖先前参数中相同名称的属性。

_.extend(destination, *sources) 

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

dojo中 ,2对象/数组“merge”将是lang.mixin(destination, source) - 您还可以将多个源混合到一个目标等中 - 有关详细信息,请参阅mixin函数的参考

Rolling Your Own Extend/Mixin Function 滚动你自己的扩展/混合功能

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

... ...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

... ...

This simply extends a splat of objects, recursively. 这仅仅简单地扩展对象的图示 ,递归。 Also, note that this recursive function is TCO ( Tail-Call Optimized ) as its return is the last call to itself. 另请注意,此递归函数是TCO( Tail-Call Optimized ),因为它的返回是对自身的最后一次调用。

Additionally, you may want targeted properties . 此外,您可能需要目标属性 In this case, you may want to condense objects based upon id , quantity , or another property. 在这种情况下,您可能希望根据idquantity或其他属性压缩对象。 This approach could have a small book written about it and requires object-juxtaposition and can get very complex. 这种方法可能有一本关于它的小书,需要对象并置,并且可能变得非常复杂。 I've written a small library for this which is available upon request. 我已经为此编写了一个小型库,可根据要求提供。

Hope this helps! 希望这可以帮助!

do you want to overwrite a property if the names are the same but the values are not? 如果名称相同但值不是,是否要覆盖属性?

And do you want to permanently change one of the original objects, 你想永久改变一个原始对象,

or do you want a new merged object returned? 或者你想要一个新的合并对象返回?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}
  1. In Javascript there is no notion of associative array, there are objects 在Javascript中没有关联数组的概念,有对象
  2. The only way to merge two objects is to loop for their properties and copy pointers to their values that are not primitive types and values for primitive types to another instance 合并两个对象的唯一方法是循环其属性并将指针复制到非基本类型的值,将基本类型的值复制到另一个实例

jquery has a boolean for deep copy. jquery有一个深度复制的布尔值。 You could do something like that: 你可以这样做:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

Also you can edit this function to support n-arrays to merge. 您也可以编辑此函数以支持n阵列合并。

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

So now you can do 所以现在你可以做到

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

Yahoo UI (YUI) also has a helper function for this: Yahoo UI(YUI)也有一个辅助函数:

http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html

YAHOO.namespace('example');

YAHOO.example.set1 = { foo : "foo" };
YAHOO.example.set2 = { foo : "BAR", bar : "bar" };
YAHOO.example.set3 = { foo : "FOO", baz : "BAZ" };

var Ye = YAHOO.example;

var merged = YAHOO.lang.merge(Ye.set1, Ye.set2, Ye.set3);

In 2019 you have 2 good options: 在2019年,您有两个不错的选择:

Object assigning [ doc ] 对象分配 [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

Object spreading [ doc ] 对象传播 [ doc ]

const result = { ...baseObject, ...updatingObject};

The first one tends to be safer, more standard and polyvalent. 第一种趋向于更安全,更标准和多价。 A good pros and cons here 这里有利有弊

I needed a deep-object-merging. 我需要一个深层对象合并。 So all of the other answers didn't help me very much. 所以其他所有答案对我都没有帮助。 _.extend and jQuery.extend do well, unless you have a recursive array like i do. _.extend和jQuery.extend做得很好,除非你像我一样有一个递归数组。 But it ain't so bad, you can program it in five minutes: 但它不是那么糟糕,你可以在五分钟内编程:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

To merge arrays in jQuery what about $.merge? 要在jQuery中合并数组,有什么关于$ .merge的?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

Recursive solution (extends also arrays of objects) + null checked 递归解决方案(也扩展了对象数组)+ null检查

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

Tests 测试

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

Here is the best solution. 这是最好的解决方案。

obj1.unshift.apply( obj1, obj2 );

Also, obj1 can grow inside a loop without any problem. 此外, obj1可以在循环内生长而没有任何问题。 (lets say obj2 is dynamic) (假设obj2是动态的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM