Як об'єднати властивості з декількох об’єктів 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 вважала це помилкою і буде її виправляти.
Хуан Мендес

Відповіді:


159

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}, ....])
Jeanluca Scaljeri

1
Альтернативою для використання Object.assign.applyдля об'єднання масиву об’єктів є використання оператора розкидання:Object.assign( ...objects )
Spen

@ Відкрийте, що вже включено як відповідь на це питання. Я не бачив вигоди дублювати це тут.
filoxo

через 4 години ця відповідь вирішила мою проблему в кутовій 7. Дякую за простоту та точність відповіді.
Гель

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. Доступ до властивості довжини коштує так само, як і доступ до змінної len.
Alsciende

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

2
Хіба не було б краще писати «за (var p in ...» замість «for (p in ...»?)
Гюго


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 (об’єкт, * за замовчуванням)

Заповніть невизначені властивості в об’єкті зі значеннями об'єктів за замовчуванням та поверніть об’єкт .

_.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
Приємно. Це питання вже більше 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); 

комбіновані_об'єкт і об’єкт1 містять властивості 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); 

У цьому випадку комбінований_об'єкт містить властивості 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' }
}

це було рішення, яке я знайшов (все ще треба проповідувати: /)

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.