Как объединить свойства из нескольких объектов 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. Но именно так это реализовано в большинстве браузеров. (От Джона Ресига) Это поведение явно не определено спецификацией ECMAScript. В ECMA-262, раздел 12.6.4: Механика перечисления свойств ... зависит от реализации. Однако спецификация сильно отличается от реализации. Все современные реализации ECMAScript перебирают свойства объекта в том порядке, в котором они были определены. Из-за этого команда Chrome сочла это ошибкой и будет исправлять ее.
— Хуан Мендес,

Ответы:


162

ECMAscript 6 введен Object.assign()для достижения этой цели изначально в Javascript.

Метод Object.assign () используется для копирования значений всех перечислимых собственных свойств из одного или нескольких исходных объектов в целевой объект. Он вернет целевой объект.

Документация MDN по 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поддерживается во многих современных браузерах, но еще не во всех. Используйте транспилятор, такой как Babel и Traceur, для создания обратно совместимого кода ES5 JavaScript.


4
Это одно из лучших, что я могу сказать. Поскольку сейчас в основном используется E6, Object.assign - лучший ответ.
— Vimalraj Selvam

6
Если вы не знаете, сколько объектов нужно объединить, поскольку они находятся в массиве, вы можете объединить их следующим образом:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
— Жанлука Скальери

1
Альтернативой Object.assign.applyобъединению массива объектов является использование оператора распространения:Object.assign( ...objects )
— Spen,

@Spen, который уже включен в качестве ответа на этот вопрос. Я не вижу пользы в дублировании этого здесь.
— filoxo 06

через 4 часа этот ответ решил мою проблему в Angular 7. Спасибо за простоту и точность ответа.
— Gel

35

Вы можете использовать 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)
<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

1
Нет, разве что в IE6. Доступ к свойству length стоит так же, как доступ к переменной len.
— Alsciende,

1
@Juan Я считаю, что вы ошибаетесь, и я сделал несколько тестов, чтобы принять решение. Кэширование длины - это простой миф об оптимизации, который устарел уже много лет и делает код (немного) менее читаемым. Собственно, кеширование длины иногда тормозит браузер (Safari).
— Alsciende,

2
Разве не лучше было бы написать «for (var p in ...» вместо «for (p in ...»?)
— Хьюго


12

У Underscore есть несколько способов сделать это;

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 (объект, * по умолчанию)

Заполните неопределенные свойства в объекте значениями из объектов по умолчанию и верните объект .

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

Оператор распространения (...) поддерживается во многих современных браузерах, но не во всех.

Поэтому рекомендуется использовать транспилятор, такой как 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

3

Оператор распространения ES7 для объекта легко использовать , в консоли браузера введите

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

1
Ницца. Этому вопросу больше 10 лет, рад, что такая простая операция теперь стала легкой. Раньше это было не так просто, если вы посмотрите на ответы других людей.
— Влад

поэтому оставил свой ответ :)
— Пурхало Алексей

2

Чтобы объединить динамическое количество объектов, мы можем использовать синтаксисObject.assign с расширением .

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

Вышеупомянутая функция принимает любое количество объектов, объединяя все их свойства в новый объект со свойствами из более поздних объектов, перезаписывая свойства из предыдущих объектов.

Демо:

Для объединения массива объектов можно применить аналогичный метод.

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

Демо:


1

Вероятно, самый быстрый, эффективный и более общий способ - это (вы можете объединить любое количество объектов и даже скопировать в первый -> назначить):

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 передаются по ссылке.


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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.