如何连接来自多个 JavaScript 对象的属性

Posted

技术标签:

【中文标题】如何连接来自多个 JavaScript 对象的属性【英文标题】:How to concatenate properties from multiple JavaScript objects 【发布时间】:2011-01-28 02:21:52 【问题描述】:

我正在寻找“添加”多个 javascript 对象(关联数组)的最佳方式。

例如,给定:

a =  "one" : 1, "two" : 2 ;
b =  "three" : 3 ;
c =  "four" : 4, "five" : 5 ;

什么是最好的计算方法:

 "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 

【问题讨论】:

语义说明:尽管有 [] 语法,但它们根本不是数组。订单并不能真正得到保证。 不保证每个 ecma 标准的迭代顺序。但这是在大多数浏览器中实现的方式。 (来自 John Resig)ECMAScript 规范明确未定义此行为。在 ECMA-262 中,第 12.6.4 节:枚举属性的机制 ... 取决于实现。但是,规范与实现有很大不同。 ECMAScript 的所有现代实现都按照定义的顺序遍历对象属性。因此,Chrome 团队认为这是一个错误,并将对其进行修复。 【参考方案1】:

要合并动态数量的对象,我们可以使用Object.assign 和spread syntax。

const mergeObjs = (...objs) => Object.assign(, ...objs);

上述函数接受任意数量的对象,将它们的所有属性合并到一个新对象中,之后对象的属性会覆盖之前对象的属性。

演示:

const mergeObjs = (...objs) => Object.assign(, ...objs);
const a = prop: 1, prop2: '2',
      b = prop3: 3, prop4: [1,2,3,4]
      c = prop5: 5,
      d = prop6: true, prop7: -1,
      e = prop1: 2;
const abcd = mergeObjs(a,b,c,d);
console.log("Merged a,b,c,d:", abcd);
const abd = mergeObjs(a,b,d);
console.log("Merged a,b,d:", abd);
const ae = mergeObjs(a,e);//prop1 from e will overwrite prop1 from a
console.log("Merged a,e:", ae);

要合并对象数组,可以应用类似的方法。

const mergeArrayOfObjs = arr => Object.assign(, ...arr);

演示:

const mergeArrayOfObjs = arr => Object.assign(, ...arr);
const arr = [
  a: 1, b: 2,
  c:1, d:3,
  abcd: [1,2,3,4], d: 4
];
const merged = mergeArrayOfObjs(arr);
console.log(merged);

【讨论】:

【参考方案2】:

在浏览器控制台中对对象使用 ES7 扩展运算符很容易

( name: "Alex", ...(true  ?  age: 19  :  )) // name: "Alex", age: 19
( name: "Alex", ...(false ?  age: 19  :  )) // name: "Alex",        

【讨论】:

不错。这个问题已有十多年的历史了,很高兴现在这样简单的操作很容易。如果你看看其他人的答案,以前并不那么容易。 这就是为什么我留下自己的答案:)【参考方案3】:

ECMAScript 6 有spread syntax。现在你可以这样做了:

const obj1 =  1: 11, 2: 22 ;
const obj2 =  3: 33, 4: 44 ;
const obj3 =  ...obj1, ...obj2 ;

console.log(obj3); // 1: 11, 2: 22, 3: 33, 4: 44

【讨论】:

这应该是公认的答案,因为它是最现代的。 Object.assign 现在已经很老了,不像这个那么可读。 是的,但是如果你有一个对象数组怎么办。分配你可以只做Object.assign(, ...objcs)Object.assign.apply(, objcs)【参考方案4】:

应该这样做:

function collect() 
  var ret = ;
  var len = arguments.length;
  for (var i = 0; i < len; i++) 
    for (p in arguments[i]) 
      if (arguments[i].hasOwnProperty(p)) 
        ret[p] = arguments[i][p];
      
    
  
  return ret;


let a =  "one" : 1, "two" : 2 ;
let b =  "three" : 3 ;
let c =  "four" : 4, "five" : 5 ;

let d = collect(a, b, c);
console.log(d);

输出:


  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5

【讨论】:

length 不是在每次调用时查找数组的大小吗?我已经习惯了写for (var i = 0, len = array.length; i &lt; len; ++i),以至于我不记得为什么我开始这样做了。 是的,没错。将长度缓存一次会更好。但是,由于参数“数组”的大小不可能很大,所以在这种情况下并不重要。 不,除了在 IE6 上略有不同。访问长度属性的成本与访问 len 变量的成本相同。 @Juan 我相信你是不正确的,我做了一些测试来下定决心。缓存长度是一个简单的优化神话,已经过时多年,它使代码(稍微)不那么可读。实际上,缓存长度有时会降低浏览器 (Safari) 的速度。 写 'for (var p in...' 而不是 'for (p in...' 不是更好吗?【参考方案5】:

ECMAscript 6 引入了Object.assign() 以在 Javascript 中实现这一点。

Object.assign() 方法用于将所有可枚举自身属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

MDN documentation on Object.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 

Object.assign is supported in many modern browsers 但还不是全部。使用像 Babel 和 Traceur 这样的编译器来生成向后兼容的 ES5 JavaScript。

【讨论】:

这是我能说的最好的之一。由于现在主要使用 E6,因此 Object.assign 是最佳答案。 如果您不知道需要合并多少个对象,因为它们在一个数组中,您可以将它们合并如下:Object.assign.apply(, [a: 1, b: 2, ....]) 使用 Object.assign.apply 合并对象数组的替代方法是使用扩展运算符:Object.assign( ...objects ) @Spen 已包含在此问题的答案中。我没有看到在这里复制它有什么好处。 4 小时后,这个答案解决了我在 Angular 7 中的问题。感谢答案的简单和准确。【参考方案6】:

你可以像这样使用 jquery 的$.extend

let a =  "one" : 1, "two" : 2 ,
    b =  "three" : 3 ,
    c =  "four" : 4, "five" : 5 ;

let d = $.extend(, a, b, c)

console.log(d)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

+1 即使您不使用 jQuery 的方法,您也可以使用他们的代码来帮助构建您自己的(也许更具体的)实现。 @Randal:不使用 jQuery 有很多非常好的理由。 编辑:d = $.extend(,a,b,c);【参考方案7】:

现在可以使用比Object.assign() 更短的语法进行对象的浅克隆(不包括原型)或合并。

Spread syntax for object literals 在ECMAScript 2018 中引入):

const a =  "one": 1, "two": 2 ;
const b =  "three": 3 ;
const c =  "four": 4, "five": 5 ;

const result = ...a, ...b, ...c;
// Object  "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 
many modern browsers 支持

扩展 (...) 运算符,但不是全部。

因此,建议使用 transpiler(如 Babel)将 ECMAScript 2015+ 代码转换为当前和旧版浏览器或环境中向后兼容的 JavaScript 版本。

这是您的等效代码Babel will generate:

"use strict";

var _extends = Object.assign || function(target) 
  for (var i = 1; i < arguments.length; i++) 
    var source = arguments[i];
    for (var key in source) 
      if (Object.prototype.hasOwnProperty.call(source, key)) 
        target[key] = source[key];
      
    
  
  return target;
;

var a =  "one": 1, "two": 2 ;
var b =  "three": 3 ;
var c =  "four": 4, "five": 5 ;

var result = _extends(, a, b, c);
// Object  "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 

【讨论】:

这是一个比公认的答案更可靠的答案。谢谢!【参考方案8】:

ES6 ++

问题是将各种不同的对象合二为一。

let obj = ;
const obj1 =  foo: 'bar' ;
const obj2 =  bar: 'foo' ;
Object.assign(obj, obj1, obj2);
//output => foo: 'bar', bar: 'foo';

假设您有一个具有多个作为对象的键的对象:

let obj = 
  foo:  bar: 'foo' ,
  bar:  foo: 'bar' 

这是我找到的解决方案(仍然需要 foreach :/)

let objAll = ;

Object.values(obj).forEach(o => 
  objAll = ...objAll, ...o;
);

通过这样做,我们可以将所有对象键动态添加到一个中。

// Output =>  bar: 'foo', foo: 'bar' 

【讨论】:

【参考方案9】:

最简单的:传播运算符

var obj1 = a: 1
var obj2 = b: 2
var concat =  ...obj1, ...obj2  //  a: 1, b: 2 

【讨论】:

【参考方案10】:

可能,最快、最有效和更通用的方式是这样的(你可以合并任意数量的对象,甚至复制到第一个 -> 分配):

function object_merge()
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];

它还允许您修改通过引用传递的第一个对象。 如果您不想要这个但想要一个包含所有属性的全新对象,那么您可以将 作为第一个参数传递。

var object1=a:1,b:2;
var object2=c:3,d:4;
var object3=d:5,e:6;
var combined_object=object_merge(object1,object2,object3); 

combined_object 和 object1 都包含 object1,object2,object3 的属性。

var object1=a:1,b:2;
var object2=c:3,d:4;
var object3=d:5,e:6;
var combined_object=object_merge(,object1,object2,object3); 

在这种情况下,combined_object 包含 object1,object2,object3 的属性,但 object1 没有被修改。

在这里查看:https://jsfiddle.net/ppwovxey/1/

注意:JavaScript 对象是通过引用传递的。

【讨论】:

【参考方案11】:

Underscore 有几个方法可以做到这一点;

1. _.extend(destination, *sources)

source 对象中的所有属性复制到 destination 对象,并返回 destination 对象。

_.extend(a, _.extend(b, c));
=> "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 

或者

_.extend(a, b);
=> "one" : 1, "two" : 2, "three" : 3
_.extend(a, c);
=> "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 

2。 _.defaults(object, *defaults)

defaults 对象中的值填充 object 中的 undefined 属性,并返回 object

_.defaults(a, _.defaults(b, c));
=> "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 

或者

_.defaults(a, b);
=> "one" : 1, "two" : 2, "three" : 3
_.defaults(a, c);
=> "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 

【讨论】:

【参考方案12】:

为什么函数应该限制为 3 个参数?另外,检查hasOwnProperty

function Collect() 
    var o=;
    for(var i=0;i<arguments.length;i++) 
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) 
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      
    
    return o;

【讨论】:

【参考方案13】:
function collect(a, b, c)
    var d = ;

    for(p in a)
        d[p] = a[p];
    
    for(p in b)
        d[p] = b[p];
    
    for(p in c)
        d[p] = c[p];
    

    return d;

【讨论】:

【参考方案14】:
function Collect(a, b, c) 
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;

注意:之前对象中的现有属性将被覆盖。

【讨论】:

这有最后a === d 的副作用。这可能没问题,也可能不行。

以上是关于如何连接来自多个 JavaScript 对象的属性的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 将来自多个节点的属性连接成单个值

JavaScript高级 对象 函数 回调函数 IIFE

如何获取 JavaScript 对象的所有属性值(不知道键)?

JavaScript快速入门-ECMAScript本地对象(Array)

如何在javascript中按属性查找数组中的对象?

如何在javascript中按属性查找数组中的对象?