Object.assign()

El método Object.assign() se utiliza para copiar los valores de todas la propiedades enumerables de uno o más objetos fuente a un objeto destino. Retorna el objeto destino. 

Sintaxis

Object.assign(objetivo, ...fuentes)

Parámetros

objetivo
El objeto destino.
fuentes
Los objetos origen.

Valor devuelto

El objeto destino.

Descripción

Las propiedades en el objeto destino serán sobrescritas por las propiedades en las fuentes si tienen la misma clave. Propiedades posteriores de las fuentes podrán sobrescribir las anteriores.

El método Object.assign() copia sólo las propiedades enumerables y propias del objeto origen a un objeto destino. Usa [[Get]] en la origen y [[Set]] en el destino, por lo que invocará los métodos de acceso y establecimiento (getters y setters). Por consiguiente asignará propiedades frente a sólo copiar o definir propiedades nuevas. Esto puede hacer que sea inadecuado para fusionar propiedades nuevas en un prototipo si los objetos fuente contienen métodos de acceso (getters). Para copiar definiciones de propiedades en prototipos, incluyendo su enumerabilidad, se deben usar Object.getOwnPropertyDescriptor() y Object.defineProperty().

Tanto las propiedades String como Symbol son copiadas.

En caso de un error, por ejemplo si una propiedad es de solo lectura, se lanza un TypeError, y el objeto destino se mantendrá sin cambios.

Note que Object.assign() no lanza excepciones al encontrar en las fuentes propiedades nullundefined.

Ejemplos

Clonando un objeto

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

Advertencia para clonado profundo

Para un clonado profundo, necesitamos usar otra alternativa ya que Object.assign() copia valores de propiedades. Si el valor en la fuente es una referencia a un objeto, solo se copia la referencia en sí, como valor.

function test() {
  "use strict";
  let a = { b: {c:4} , d: { e: {f:1}} };
  let g = Object.assign({},a);
  let h = JSON.parse(JSON.stringify(a));
  console.log(JSON.stringify(g.d)); // { e: { f: 1 } }
  g.d.e = 32;
  console.log("g.d.e set to 32."); // g.d.e set to 32.
  console.log(JSON.stringify(g)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(a)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(h)); // { b: { c: 4 }, d: { e: { f: 1 } } }
  h.d.e = 54;
  console.log("h.d.e set to 54."); // h.d.e set to 54.
  console.log(JSON.stringify(g)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(a)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(h)); // { b: { c: 4 }, d: { e: 54 } }
}
test();

Fusionando objetos

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 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, se ha cambiado el objeto destino.

Fusionando objetos con propiedades similares

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3

Las propiedades también son sobreescritas por otros objetos que aparecen posteriormente en la lista de parámetros y que tienen propiedades con el mismo nombre.

Copiando propiedades de tipo símbolo

var o1 = { a: 1 };
var o2 = { [Symbol('foo')]: 2 };

var obj = Object.assign({}, o1, o2);
console.log(obj); // { a: 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]

Las propiedades heredadas y las no enumerables no pueden ser copiadas

var obj = Object.create({ foo: 1 }, { // foo es una propiedad heredada.
  bar: {
    value: 2  // bar es una propiedad no enumerable.
  },
  baz: {
    value: 3,
    enumerable: true  // baz es una propiedad propia enumerable.
  }
});

var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

Los tipos primitivos serán encapsulados en objetos

var v1 = 'abc';
var v2 = true;
var v3 = 10;
var v4 = Symbol('foo')

var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
// Los tipos primitivos son encapsulados en objetos y se
// ignoran las propiedades con valor null o undefined.
// Nótese que solo los wrappers de cadenas tienen propiedades 
// enumerables:
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

Las excepciones interrumpen la tarea de copiado

var target = Object.defineProperty({}, 'foo', {
  value: 1,
  writeable: false
}); // target.foo es una propiedad de solo lectura

Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" es de solo lectura
// La excepción se lanza cuando se intenta asignar un valor a target.foo

console.log(target.bar);  // 2, la primera fuente fue copiada.
console.log(target.foo2); // 3, la primera propiedad del segundo objeto fuente se copió correctamente.
console.log(target.foo);  // 1, se lanza la excepción.
console.log(target.foo3); // undefined, el método assign ha finalizado, no se copiará foo3.
console.log(target.baz);  // undefined, tampoco se copiará el tercer objecto fuente.

Copiando métodos de acceso.

var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

var copy = Object.assign({}, obj); 
console.log(copy); 
// { foo: 1, bar: 2 }, el valor de copy.bar es el valor de retorno del getter de obj.bar.

// Esta funcion copia los descriptores en su totalidad
function completeAssign(target, ...sources) {
  sources.forEach(source => {
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});
    // por defecto, Object.assign copia las propiedades de tipo Symbol que sean enumerables
    Object.getOwnPropertySymbols(source).forEach(sym => {
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

Polyfill

Este polyfill no soporta propiedades símbolo, ya que ES5 no tiene símbolos.

if (typeof Object.assign != 'function') {
  Object.assign = function (target, varArgs) { // .length of function is 2
    'use strict';
    if (target == null) { // TypeError if undefined or null
      throw new TypeError('Cannot convert undefined or null to object');
    }

    var to = Object(target);

    for (var index = 1; index < arguments.length; index++) {
      var nextSource = arguments[index];

      if (nextSource != null) { // pasamos si es undefined o null
        for (var nextKey in nextSource) {
          // Evita un error cuando 'hasOwnProperty' ha sido sobrescrito
          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }
    return to;
  };
}

Especificaciones

Especificación Estado Comentario
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Object.assign' in that specification.
Standard Definición inicial
ECMAScript Latest Draft (ECMA-262)
The definition of 'Object.assign' in that specification.
Draft  

Compatibilidad en navegadores

Característica Chrome Firefox (Gecko) Internet Explorer Edge Opera Safari
Soporte básico 45 34 (34) No support (Yes) 32 9
Característica Android Chrome para Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Soporte básico No support 45 34.0 (34) No support No support (Yes)

Ver también

Etiquetas y colaboradores del documento

 Última actualización por: AlePerez92,