Як злити два об'єкти 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.