如何串联来自多个JavaScript对象的属性


105

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

例如,给定:

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

什么是最好的计算方式:

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

3
语义上的注释:尽管使用[]语法,但它们根本不是数组。不能真正保证订单。
阿尔瓦罗·冈萨雷斯

1
根据ecma标准,不能保证迭代顺序。但这是大多数浏览器中实现的方式。(摘自John Resig)ECMAScript规范明确未定义此行为。在ECMA-262中的第12.6.4节:枚举属性...的机制取决于实现。但是,规范与实现完全不同。ECMAScript的所有现代实现都按照定义它们的顺序遍历对象属性。因此,Chrome小组认为这是一个错误,并将予以修复。
Juan Mendes

Answers:


159

引入ECMAscript 6是Object.assign()为了用Javascript本身实现此目的。

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

关于Object.assign()的MDN文档

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在许多现代浏览器中都受支持,但并非所有浏览器都支持。使用Babel和Traceur等编译器来生成向后兼容的ES5 JavaScript。


4
这是我能说的最好的之一。由于现在最常使用E6,因此Object.assign是最佳答案。
Vimalraj Selvam

6
如果您不知道需要合并多少个对象,因为它们位于数组中,因此您可以按以下步骤进行合并:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri,

Object.assign.apply用于合并对象数组的一种替代方法是改为使用散布运算符:Object.assign( ...objects )
Spen

@Spen已经作为该问题的答案被包括在内。在这里复制它没有好处。
filoxo '18

4小时后,此答案在Angular 7中解决了我的问题。感谢答案的简单性和准确性。
凝胶

35

您可以$.extend像这样使用jquery :

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

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

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


+1即使您不使用jQuery的方法,也可以使用它们的代码来帮助构造自己的(也许是更具体的)实现。
tvanfosson

25
@Randal:不使用jQuery的理由很多。
蒂姆·唐

3
编辑:d = $.extend({},a,b,c);
鲍勃·斯坦因

34

应该这样做:

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 < len; ++i),以至于我不记得为什么开始这么做。
tvanfosson

1
对,那是正确的。一次缓存长度会更好。但是,由于参数“数组”的大小不可能很大,因此在这种情况下并不重要。
jhurshman 2010年

1
不,除了IE6略有不同。访问length属性的费用与访问len变量的费用相同。
Alsciende

1
@Juan我相信您是错误的,并且我做了一些测试来下定决心。缓存长度是一个简单的优化神话,它已经过了很多年了,并且使代码(略)不易读。实际上,缓存长度有时会降低浏览器(Safari)的速度。
Alsciende 2010年

2
写'for(var p in ...'而不是'for(p in ...')吗?
Hugo

24

ECMAScript 6具有扩展语法。现在,您可以执行以下操作:

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}


12

下划线几乎没有方法可以做到这一点;

1. _.extend(目的地,*来源)

对象中的所有属性复制到目标对象,然后返回目标对象。

_.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(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 }

4

为什么将函数限制为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;
}

4

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

扩展语法对象文本在引入的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 }

许多现代浏览器都支持Spread(...)运算符,但并非所有浏览器都支持。

因此,建议在当前和较旧的浏览器或环境中使用类似Babel编译器将ECMAScript 2015+代码转换为JavaScript的向后兼容版本。

这是Babel将为生成的等效代码:

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

这是一个比接受的答案更可靠的答案。谢谢!
卡莱布·安德森

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

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

    return a;
}

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


2
最后有副作用a === d。可能可以,但可能不能。
tvanfosson

2

在浏览器控制台中将ES7传播运算符用于对象很容易

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

1
真好 这个问题已有十多年的历史了,很高兴现在这样简单的操作很容易。如果您看看其他人的答案,那并不是那么容易。
弗拉德

这就是为什么我留下自己的答案的原因:)
Purkhalo Alex

1

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

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包含对象1,对象2,对象3的属性,但对象1未被修改。

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

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


1

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

1

若要合并对象的动态数量,我们可以使用Object.assign传播的语法

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

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

演示:

为了合并对象的阵列,可以应用类似的方法。

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

演示:



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.