Как мне объединить два объекта javascript вместе в ES6 +?

145

Мне надоело всегда писать такой код:

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
13
@RobG, этот вопрос касается надежды, что ES6 избавит нас от необходимости в такой шаблонной чуши, в первую очередь. Для чего это стоит: github.com/balupton/bal-util/blob/…
balupton
Я не думаю, что есть общий способ скопировать пары имя / значение из одного объекта в другой. Вы имеете дело только с собственностью или с недвижимостью в [[Prototype]]сети? Вы делаете «глубокие» или «мелкие» копии? А как насчет неперечислимых и недоступных для записи свойств? Думаю, мне бы хотелось иметь небольшую библиотечную функцию, которая делает то, что мне нужно, и в большинстве случаев ее все равно можно избежать.
RobG

Ответы:

209

Вы сможете выполнить мелкое слияние / расширение / назначение в ES6 с помощью Object.assign:

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

Синтаксис:

Object.assign ( цель , источники );

где ... sources представляют исходный объект (ы).

Пример:

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

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true
Джек
источник
66
Небольшое примечание: Object.assign изменяет цель. Если это не то, что вы хотите, вы можете вызвать его с помощью пустого объекта:let merged = Object.assign({}, source1, source2);
Дэвид
20
Обратите внимание, это неглубокое расширение ... вложенные объекты НЕ объединяются
monzonj
@monzonj, разве нет возможности расширять вложенные объекты без использования lodash или mout?
Жоао Фалькао
1
Есть хороший способ объединить глубоко вложенные объекты без библиотеки, используя только Object.assign: см. Мой ответ здесь
Руслан
Используется старый способ расширения вложенных объектовJSON.parse(JSON.stringify(src))
Андре Фигейредо
166

Для этого можно использовать синтаксис распространения объекта :

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

Для массивов оператор распространения уже был частью ES6 (ES2015), но для объектов он был добавлен в спецификацию языка на ES9 (ES2018). Его предложение было включено по умолчанию в таких инструментах, как Babel, задолго до этого.

Тийс Керсельман
источник
3
Нет, официально он сейчас называется ES2015: P С каких это пор деструктуризация не является частью ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Запуск babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Вывод:{ foo: 123, bar: 234 }
Тийс Керсельман
9
Это не деструктуризация, это распространение - и нет, для объектов это не часть ES6. Вы должны отключить экспериментальные черновики ES7 в своем babel.
Берги
2
Ах, прости меня. Ты прав. На данный момент это функция Babel Stage 2. github.com/sebmarkbage/ecmascript-rest-spread Я никогда не осознавал этого, потому что я использовал его с самого начала с babel, и он включен по умолчанию. Но так как вам все равно нужно транспилировать, а распространение объекта - довольно простая вещь, я все равно рекомендую это. Я люблю это.
Thijs Koerselman
Они действительно включены по умолчанию? Звучит как ошибка.
Берги
2
«Предложения, находящиеся на стадии 2 или выше, включены по умолчанию». babeljs.io/docs/usage/experimental
Thijs Koerselman 05
14

Я знаю, что это немного старая проблема, но самое простое решение в ES2015 / ES6 на самом деле довольно простое, используя Object.assign (),

Надеюсь, это поможет, это также ГЛУБОКОЕ слияние:

/**
 * 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-De December/027037.html

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

Натан Уолл
источник
5
Предупреждение - этот ответ больше неверен, см. Ответ Джека для правильного и рабочего подхода.
Бенджамин Грюнбаум
Object.mixin был заменен на Object.assign
gotofritz 09
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 / underscore.
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) приведет к неожиданным результатам.
Balupton
также придется использовать Object.getOwnPropertyDescriptorдля установки свойства, когда это сложное значение, или вы будете копировать по ссылке.
dmp