Як злити два об'єкти javascript разом у ES6 +?


141

Мені набридло завжди писати такий код:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

Або якщо я не хочу самостійно писати код, застосуйте бібліотеку, яка вже це робить. Безумовно, ES6 + приходить на допомогу в цьому, забезпечить нам щось на зразок Object.prototype.extend(obj2...)абоObject.extend(obj1,obj2...)

Так ES6 + надає таку функціональність? Якщо вже немає, то планується така функціональність? Якщо не планується, то чому б ні?


3
То чому ви не додали його до своєї бібліотеки?
— RobG

12
@RobG це питання стосується сподівання, що ES6 позбавить нас від необхідності в першу чергу таких лайневих котлів. Для чого це варто: github.com/balupton/bal-util/blob/…
— balupton

Я не думаю, що існує загальний спосіб копіювання пар імен / значень з одного об’єкта на інший. Чи маєте ви справу лише з власними властивостями або тими, що на [[Prototype]]ланцюжку? Ви робите "глибокі" чи "неглибокі" копії? А як щодо властивостей, що не перераховуються, і не підлягають запису? Я думаю, що я вважаю за краще мати невелику бібліотечну функцію, яка виконує те, що мені потрібно, і в основному це можна уникнути в будь-якому випадку.
— RobG

Відповіді:


206

Ви зможете зробити неглибоке злиття / розширення / призначення в ES6 за допомогою Object.assign:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Синтаксис:

Object.assign ( ціль , джерела );

де ... джерела представляють вихідний об'єкт (и).

Приклад:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
Невелика примітка: Object.assign мутує ціль. Якщо це не те, що ви хочете, ви можете назвати його порожнім об’єктом:let merged = Object.assign({}, source1, source2);
— Давид,

20
Зверніть увагу, що це
— невелике

@monzonj, чи не існує жодного варіанту розширення вкладених об'єктів без використання lodash чи mout?
— Жоао Фалькао

1
Є хороший спосіб об’єднати глибоко вкладені об’єкти без бібліотеки просто Object.assign: дивіться мою відповідь тут
— Руслан

Використовується старий спосіб розширення вкладених об’єктівJSON.parse(JSON.stringify(src))
— Андре Фігейредо

162

Ви можете використовувати для цього синтаксис розповсюдження об'єктів :

const merged = {...obj1, ...obj2}

Для масивів оператор розповсюдження вже був частиною ES6 (ES2015), але для об'єктів він був доданий до мовної специфікації на ES9 (ES2018). Його пропозиція була включена за замовчуванням в таких інструментах, як Babel, задовго до цього.


3
Офіційно зараз це не називається ES2015: P З того часу, коли деструкція не є частиною ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Запуск babel-вузла: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Вихід:{ foo: 123, bar: 234 }
— Thijs Koerselman

9
Це не руйнує, воно поширюється - і ні, для об'єктів це не частина ES6. Вам слід відключити експериментальні чернетки ES7 у вашій дитинці.
— Бергі

2
А пробач мене. Ти правий. Наразі це особливість вавилонської стадії 2. github.com/sebmarkbage/ecmascript-rest-spread Я ніколи не усвідомлював цього, тому що використовую його з самого початку з бабелом, і це за умовчанням увімкнено. Але оскільки вам потрібно все-таки транспілювати, а розповсюдження об'єкта - це досить проста річ, я все одно рекомендував би його. Я це люблю.
— Thijs Koerselman

Вони включені за замовчуванням, справді? Це звучить як помилка.
— Бергі

2
"Пропозиції, які є на етапі 2 або вище, увімкнено за замовчуванням". babeljs.io/docs/usage/experimental
— Thijs Koerselman

14

Я знаю, що це трохи стара проблема, але найпростіше рішення в ES2015 / ES6 насправді досить просте, використовуючи Object.assign (),

Сподіваємось, це допомагає, і це злиття DEEP :

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

Приклад використання:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

7

В Object.mixinданий час обговорюється додаток, щоб подбати про поведінку, про яку ви просите.https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Хоча його ще немає в проекті ES6, схоже, існує велика підтримка, тому я думаю, що незабаром він з’явиться в чернетках.



5
Попередження - ця відповідь більше не є правильною, див. Відповідь Джека щодо правильного та робочого підходу.
— Бенджамін Грюнбаум

Object.mixin був замінений Object.assign
— gotofritz

7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 або Babel

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi це не ES6, з яким ви пов’язані. Але в основному це робить еквівалент _.extend () у lodash / підкресленні.
— Nostalg.io

5

Можливо, Object.definePropertiesметод ES5 зробить цю роботу?

напр

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

Документація MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


Але будьте обережні. За принаймні , один браузер це впливає на продуктивність.
— Рувен Морає

1
Думаю, найцікавіша частина - це definePropertiesвизначення власних властивостей. Він не переписує властивості в [[prototype]]ланцюжку, він затінює їх.
— RobG

2
Хороша пропозиція, хоча насправді не є розширенням, оскільки це більше для визначення способів поведінки властивостей ... Виконання прямого Object.defineProperties (obj1, obj2) призведе до несподіваних результатів.
— балуптон

доведеться Object.getOwnPropertyDescriptorтакож використовувати для встановлення властивості, коли це складне значення, або ви скопіюєте за посиланням.
— dmp
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.