¿Cómo combino dos objetos javascript juntos en ES6 +?


141

Estoy cansado de tener que escribir siempre código como este:

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

O si no quiero escribir el código yo mismo, implemente una biblioteca que ya lo haga. Seguramente ES6 + vendrá al rescate en esto nos proporcionará algo así como un Object.prototype.extend(obj2...)oObject.extend(obj1,obj2...)

Entonces, ¿ES6 + proporciona esa funcionalidad? Si aún no está allí, ¿se planifica dicha funcionalidad? Si no está planeado, ¿por qué no?


3
Entonces, ¿por qué no lo has agregado a tu biblioteca?
— RobG

12
@RobG, esta pregunta trata sobre la esperanza de que ES6 nos elimine de tener que necesitar esa basura repetitiva en primer lugar. Por lo que vale: github.com/balupton/bal-util/blob/…
— balupton

No creo que haya una forma general de copiar los pares de nombre / valor de un objeto a otro. ¿Solo trata con propiedades propias o de la [[Prototype]]cadena? ¿Haces copias "profundas" o "superficiales"? ¿Qué pasa con las propiedades no enumerables y no editables? Creo que prefiero tener una pequeña función de biblioteca que haga lo que necesito, y sobre todo es evitable de todos modos.
— RobG

Respuestas:


206

Podrá hacer una fusión / extensión / asignación superficial en ES6 utilizando Object.assign:

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

Sintaxis:

Object.assign ( objetivo , fuentes );

donde ... fuentes representa los objetos fuente.

Ejemplo:

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

Object.assign(obj1, obj2);

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

64
Una pequeña nota: Object.assign muta el objetivo. Si eso no es lo que quieres, puedes llamarlo con un objeto vacío:let merged = Object.assign({}, source1, source2);
— david

20
Tenga en cuenta que esta es una extensión superficial ... los objetos anidados NO se fusionan
— monzonj

@monzonj, ¿no hay ninguna opción para extender objetos anidados, sin usar lodash o mout?
— Joao Falcao el

1
Hay una buena manera de fusionar objetos profundamente anidados sin una biblioteca usando solo Object.assign: vea mi respuesta aquí
— Ruslan,

Una forma antigua de extender objetos anidados es usarJSON.parse(JSON.stringify(src))
— Andre Figueiredo

162

Puede usar la sintaxis de propagación de objetos para esto:

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

Para las matrices, el operador de propagación ya era parte de ES6 (ES2015), pero para los objetos se agregó a la especificación de lenguaje en ES9 (ES2018). Su propuesta fue habilitada por defecto en herramientas como Babel mucho antes de eso.


3
No, oficialmente se llama ES2015 ahora: P ¿Desde cuándo la desestructuración no forma parte de ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Ejecutando babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Salida:{ foo: 123, bar: 234 }
— Thijs Koerselman

9
Eso no es desestructuración, se está extendiendo, y no, para los objetos no es parte de ES6. Debe deshabilitar los borradores experimentales de ES7 en su babel.
— Bergi

2
Ah perdoname. Tienes razón. Es una característica de Babel Stage 2 en este momento. github.com/sebmarkbage/ecmascript-rest-spread Nunca me di cuenta de eso porque lo he estado usando desde el principio con babel y está habilitado de forma predeterminada. Pero dado que necesita transpilar de todos modos, y la propagación del objeto es algo bastante sencillo, lo recomendaría de todos modos. Me encanta.
— Thijs Koerselman

Están habilitados por defecto, ¿en serio? Eso suena como un error.
— Bergi

2
"Las propuestas que están en la etapa 2 o superior están habilitadas de forma predeterminada". babeljs.io/docs/usage/experimental
— Thijs Koerselman

14

Sé que este es un problema un poco antiguo, pero la solución más fácil en ES2015 / ES6 es bastante simple, usando Object.assign (),

Esperemos que esto ayude, esto también hace una fusión PROFUNDA :

/**
 * 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;
}

Ejemplo de uso:

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

La adición de Object.mixinse está discutiendo actualmente para cuidar el comportamiento que está solicitando. https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Aunque todavía no está en el borrador de ES6, parece que hay mucho apoyo para él, por lo que creo que aparecerá pronto en los borradores.



55
Advertencia : esta respuesta ya no es correcta; consulte la respuesta de Jack para obtener un enfoque correcto y funcional.
— Benjamin Gruenbaum

Object.mixin ha sido reemplazado por 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 o Babel

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

1
@FilipBartuzi que no es ES6 al que se vinculó. Pero básicamente está haciendo el equivalente a _.extend () en lodash / subrayado.
— Nostalg.io

5

¿Quizás el Object.definePropertiesmétodo ES5 hará el trabajo?

p.ej

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

Object.defineProperties(a, b);

alert(a.age); // 37

Documentación de MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


Pero ten cuidado. En al menos un navegador esto tiene implicaciones de rendimiento.
— Reuben Morais

1
Creo que la parte más interesante es que definePropertiesdefine propiedades propias. No sobrescribe las propiedades en la [[prototype]]cadena, las sombrea.
— RobG

2
Buena sugerencia, aunque no es realmente una extensión, ya que es más para definir cómo deben comportarse las propiedades ... Hacer un Object.defineProperties directo (obj1, obj2) causaría resultados inesperados.
— balupton

tendría que usar Object.getOwnPropertyDescriptortambién para establecer la propiedad cuando es un valor complejo, o copiará por referencia.
— dmp
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.