在 Javascript 中合并对象的本机方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4740806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:51:30  来源:igfitidea点击:

Native way to merge objects in Javascript

javascriptoptimizationprototype

提问by kristopolous

Javascript's Object doesn't have any native merge operation. If you have two objects, say

Javascript 的 Object 没有任何本机合并操作。如果您有两个对象,请说

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

And want to get

并且想要得到

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

As far as I know, you have to iterate through the objects. That is to say that you decide on either a merge left or merge right strategy and then you do something like (simplified)

据我所知,您必须遍历对象。也就是说,您决定采用左合并或右合并策略,然后执行类似(简化)的操作

for (key in object2) {
  object1[key] = object2[key];
}

This is fine. However, Javascript has the calland prototypefeature. For instance, turning argumentsinto an Arraycan be done with

这可以。但是,Javascript 具有callprototype功能。例如,arguments变成一个Array可以用

Array.prototype.slice.call(arguments)

Array.prototype.slice.call(arguments)

This approach exploits existing native code, and so therefore is less susceptible to programmer folly and should run faster than a non-native implementation.

这种方法利用现有的本机代码,因此不太容易受到程序员愚蠢的影响,并且应该比非本机实现运行得更快。

The question

问题

Is there a trick to use this prototype/call pattern on perhaps the Attributeor Nodetraversal features of the DOM, or perhaps some of the generic Stringfunctions in order to do a native object merge?

是否有一个技巧可以在 DOM的AttributeNode遍历特性上使用这种原型/调用模式,或者可能是一些通用String函数来进行本地对象合并?

The code would look something like this:

代码看起来像这样:

var merged = somethingrandom.obscuremethod.call(object1, object2)

var merged = somethingrandom.obscuremethod.call(object1, object2)

And as a result, you'd get a native merge without a traversal.

结果,您将获得无需遍历的本机合并。

A possible, sub-optimal solution

一个可能的、次优的解决方案

If you could use the constructorproperty of an Objectand then coerce one object to have a constructor of another object and then run newover the composite object, you may get a merge for free. But I don't have a firm grasp of the full implications of the constructorfeature in javascript to make this call.

如果您可以使用constructoran的属性,Object然后强制一个对象具有另一个对象的构造函数,然后运行new复合对象,则可以免费获得合并。但是我并没有完全掌握constructorjavascript中该功能的全部含义来进行此调用。

Lemma

引理

The same question holds true for Arrays. A common problem is to take, say 7 arrays of numbers, then try to find out the intersection of those arrays. That is to say, which numbers exist in all 7 arrays.

同样的问题也适用于Arrays。一个常见的问题是取 7 个数字数组,然后尝试找出这些数组的交集。也就是说,所有7个数组中都存在哪些数字。

You could concat them together, then do a sort, and then do a traversal, surely. But it would be nice if there is a generic intersect tucked away somewhere that we can coerce an array to doing natively.

当然,您可以将它们连接在一起,然后进行排序,然后进行遍历。但是,如果有一个通用的相交隐藏在某个地方,我们可以强制数组在本机上执行,那就太好了。

Any thoughts?

有什么想法吗?

edit:

编辑:

Getting half way there

半途而废

For the array problem, you could do the following:

对于数组问题,您可以执行以下操作:

array.concat(a, b, c).sort().join(':') and then use some tricky RegExpcapture and repeat patterns in order to traverse. RegExp implementations, if you don't know, run on a very simple stack-based virtual machine. When you initialize your regular expression that's really a program that gets compiled (RegExp.compile is a deprecated JS method). Then the native runs over the string in a blisteringly fast way. Perhaps you could exploit that for membership thresholds and get better performance...

array.concat(a, b, c).sort().join(':') 然后使用一些棘手的RegExp捕获和重复模式来遍历。RegExp 实现,如果您不知道,运行在一个非常简单的基于堆栈的虚拟机上。当你初始化你的正则表达式时,它实际上是一个被编译的程序(RegExp.compile 是一个不推荐使用的 JS 方法)。然后本地人以极快的方式从弦上跑过。也许您可以将其用于成员资格阈值并获得更好的性能......

It still doesn't go all the way though.

尽管如此,它仍然没有走完。

采纳答案by Jakob

My answer to this will be disappointing, but still:

我对此的回答会令人失望,但仍然:

no

The reason for this is simple: Mr Resig's implementation of merge (or "extend" as it's called for objects) in jQuery is doing a loop, just like the one in your question. You can look at it here. And I dare say that if John Resig hasn't found a clever build-in way to do it, then the mere mortals of stackoverflow won't either :)

原因很简单:Resig 先生在 jQuery 中实现合并(或“扩展”,因为它被称为对象)正在执行一个循环,就像您问题中的那个。你可以在这里查看。我敢说,如果 John Resig 还没有找到一个聪明的内置方法来做到这一点,那么 stackoverflow 的凡人也不会:)

回答by Spike Sagal

The million dollar question! I've tried doing this numerous ways, and the loop way described above always seemed the dirtiest. ES6's Object.setPrototypeOf()allows you to delegate a "property override" object to a "default properties" object, pretty much accomplishing what you're trying to do, but using Object.setPrototypeOf()has some serious implications, like disabling the browser's compiler optimizations for the whole script.

百万美元的问题!我已经尝试过很多方法,上面描述的循环方式似乎总是最脏的。ES6Object.setPrototypeOf()允许您将“属性覆盖”对象委托给“默认属性”对象,这几乎可以完成您想要做的事情,但是使用Object.setPrototypeOf()具有一些严重的影响,例如禁用浏览器对整个脚本的编译器优化。

Also, in both the loop solution and the Object.setPrototypeOf()solution, you are left with a situation where the "property override" object can mutate the "default properties" object:

此外,在循环解决方案和Object.setPrototypeOf()解决方案中,您都会遇到“属性覆盖”对象可以改变“默认属性”对象的情况:

defaultObj = {
    a: [1, 2]
}
...
overrideObj = {
    b: 3
}
Object.setPrototypeOf(overrideObj, defaultObj);
console.log(overrideObj); // {a: [1, 2], b: 3}
// Great!
...
overrideObj.a.push(4);
console.log(defaultObj); // {a: [1, 2, 4]}
// Uh-oh.

You might think this is not a problem, but let's say you're using this object as configuration for a 3rd party lib. You are now handing the control of your default object and everything referenced in it to the 3rd party lib.

您可能认为这不是问题,但假设您将此对象用作第 3 方库的配置。您现在将默认对象的控制权以及其中引用的所有内容交给 3rd 方库。

A better solution might be to use JSON.stringify and JSON.parse to copy and combine the objects. Here's a Gist with the example: https://gist.github.com/spikesagal/6f7822466887f19b9c65

更好的解决方案可能是使用 JSON.stringify 和 JSON.parse 来复制和组合对象。这是示例的要点:https: //gist.github.com/spikesagal/6f7822466887f19b9c65

HTH

HTH

回答by DanSavoy

Using ES6 (ES2015) you can use Object.assignmethod:

使用 ES6 (ES2015) 你可以使用Object.assign方法:

var x = {a:1, b:2};
var y = {c:3, d:4};
var z = Object.assign({},x,y);

Using ES7 (ES2016, Chrome 60+ or Babel) you can use Object spread operator:

使用 ES7(ES2016、Chrome 60+ 或 Babel),您可以使用对象扩展运算符

var x = {a:1, b:2};
var y = {c:3, d:4}; 
var z = {...x, ...y};

回答by Brian Donovan

Not that I know of, no. Also, you'll want to write your merge method like this:

不是我所知道的,不。此外,您还需要像这样编写合并方法:

function mergeInto(o1, o2) {
  if (o1 == null || o2 == null)
    return o1;

  for (var key in o2)
    if (o2.hasOwnProperty(key))
      o1[key] = o2[key];

  return o1;
}

回答by Ron Anon

You can do the following using native JS 1.7, without the need of a framework. See example on fiddle(example only intended for simple objects - not complex nested objects)

您可以使用原生 JS 1.7 执行以下操作,而无需框架。请参阅小提琴示例(示例仅适用于简单对象 - 不适用于复杂的嵌套对象)

var obj1 = {a: "a", b: "b"};
var obj2 = {c: "c", d: "d"};

// The magic: ugly but works perfectly
var value = (JSON.stringify(obj1).concat(JSON.stringify(obj2))).replace("}{", ",");

document.getElementById("lbl1").setAttribute("value", value);

// back to object
var obj3 = JSON.parse(value);
document.getElementById("lbl2").setAttribute("value", obj3.a + " " + obj3.b + " " + obj3.c + " " + obj3.d);

回答by Informate.it

No native ways in ECMA-Script, use:

ECMA-Script 中没有原生方式,请使用:

function merge(o1,o2) {
 if (typeof(o1)!=='object') o1={};
 if (typeof(o2)!=='object') o2={};
 for (var k in o2) {
 if (o1[k]!==undefined)
  alert ('Collision Error'); // TODO
 else
   o1[k]=o2[k];
 }
 return o1;
}

回答by cpreid

Below I've included a deep-merge function I wrote. It will not deep-merge Arrays, only Objects. It will take two objects, and return a third, new object.

下面我包含了我编写的深度合并函数。它不会深度合并数组,只会深度合并对象。它将接受两个对象,并返回第三个新对象。

var merge = function(o1, o2) {
    var o_new = {};
    for(p in o1) {
        if(o1[p]) {
            if(typeof o1[p] == 'object' && !(o1[p] instanceof Array) && o2.hasOwnProperty(p)) {
                o_new[p] = merge(o1[p], o2[p]);
            }
            else {
                o_new[p] = o1[p];
            }
        }
    }
    for(p in o2) {
        if(typeof o2[p] == 'object' && !(o2[p] instanceof Array) && o1.hasOwnProperty(p)) {
            o_new[p] = merge(o1[p], o2[p]);
        }
        else {
            o_new[p] = o2[p];
        }
    }
    return o_new;
}