¿Cómo duplicar propiedades de objeto en otro objeto?

185

Dado el objeto:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

¿Cómo puedo copiar las propiedades dentro de otro objeto ( secondObject) como este:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

utilizando una referencia a la firstObject? Algo como esto:

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

(esto no funciona ... Lo puse solo para mostrar en grandes líneas cómo me gustaría estructurar el código).

¿Es posible una solución sin usar ningún framework de JavaScript?

Igor Popov
fuente
3
Respondido aquí: stackoverflow.com/questions/171251/…
Calvin
1
La pregunta es, ¿quieres una copia superficial o profunda? Si es profundo, ¿qué tan profundo?
georg
55
FWIW, se llaman "propiedades", no "atributos".
TJ Crowder
Aquí hay algo realmente feo que funciona de todos modos (¡no se recomienda realmente! Solo una prueba de concepto de una sola línea):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee
@TJCrowder: Corrigí la pregunta ... gracias.
Igor Popov

Respuestas:

213
for(var k in firstObject) secondObject[k]=firstObject[k];
Michael Krelin - hacker
fuente
3
@BenLee, lo que te estás perdiendo aquí es que Igor ha demostrado el uso exacto que tiene para él, en el que hasOwnPropertyes inútil. Si bien considero útil su puntero, considero que la idea de aplicar cualquier regla a cualquier situación es dañina e imprudente. Al igual que todas estas prácticas de desarrollo basadas en patrones que están sucediendo, así que no lo tomes como algo personal ...
Michael Krelin - pirata informático
1
@ MichaelKrelin-hacker, lo que te estás perdiendo aquí es que StackOverflow no es solo para el beneficio del OP. Se utiliza como referencia para futuros visitantes que pueden tener casos de uso ligeramente diferentes, donde ese puntero puede ser útil.
Ben Lee
@BenLee, no soy IgorPopov ;-) Y como no soy el OP, ya dije que el puntero me parece útil y tu respuesta también, es la parte "realmente deberías estar usando" lo que no me gusta.
Michael Krelin - hacker
23
Se omite una hasOwnProperty()prueba y las cosas siguen funcionando. Hasta que se detengan, porque tus objetos se volvieron más complejos con el tiempo. Excepto que se rompe misteriosamente en una parte no relacionada del código porque se copió demasiado. Y no tiene ningún contexto para la depuración. JS apesta así, por lo que es prudente una codificación cuidadosa para evitar que ocurran tales problemas.
Eli Bendersky
2
Creo que esta respuesta debe actualizarse según el siguiente enlace developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; fuente constante = {b: 4, c: 5}; const returnTarget = Object.assign (target, source); console.log (objetivo); // salida esperada: Object {a: 1, b: 4, c: 5} console.log (returnTarget); // salida esperada: Objeto {a: 1, b: 4, c: 5}
Elbassel
170

Siguiendo el ejemplo de la respuesta de @ Bardzuśny aquí, ES6 ha entregado una solución nativa: ¡la Object.assign()función!

El uso es simple:

Object.assign(secondObject, firstObject);

¡Eso es!

El apoyo en este momento es obviamente pobre; solo Firefox (34+) lo admite de forma inmediata, mientras que Chrome (45+) y Opera (32+) requieren que se establezca el 'indicador experimental'.

El soporte está mejorando, con las últimas versiones de Chrome, Firefox, Opera, Safari y Edge que lo soportan (IE notablemente no tiene soporte). Los transpiladores también están disponibles, como Babel y Traceur. Ver aquí para más detalles.

El segador DIMM
fuente
44
+1, otra característica genial de ES6. Por supuesto, el soporte de navegador / incluso Node.JS falta por ahora, pero como mencionó, hay transpiladores disponibles. Y si no te gustan, calzas: github.com/paulmillr/es6-shim (o solo, -soloObject.assign() shim: github.com/ljharb/object.assign ).
bardzusny
1
@Xoyce Si marca la página MDN vinculada, dice claramente "Si el valor de origen es una referencia a un objeto, solo copia ese valor de referencia". Por lo tanto, conserva la referencia y no copia el objeto. Su advertencia contra el comportamiento inesperado todavía es adecuada, y se reduce a tener las expectativas adecuadas.
The DIMM Reaper
@mostafiz Revertí su edición, porque la pregunta y otras respuestas en esta página usan los nombres "firstObject" y "secondObject", así que usé los mismos nombres aquí para mayor claridad y consistencia.
The DIMM Reaper
Si esto es consistente con la pregunta, entonces está bien.
Mostafiz Rahman
1
@pdem Sí, vea la respuesta de kingPuppy .
El DIMM Reaper
101

Por ES6 - Sintaxis extendida :

Simplemente puede usar:

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

Esto evita problemas de pasar estos objetos por referencia.

Además, se ocupa de los objetos que tienen un anidamiento profundo.

reyCachorro
fuente
2
Wow, esto es realmente increíble :) Gracias por la respuesta. Obviamente, ya no lo necesito (ya que fue hace un tiempo), pero podría ayudar a alguien más.
Igor Popov
1
¡+1 para un uso aún más genial de ES6! Los documentos de MDN mencionados anteriormente no mencionan el uso del operador de propagación en los objetos, así que hice un violín para verlo en acción: es6fiddle.net/im3ifsg0
The DIMM Reaper
1
@jaepage - buen comentario para referencia. Un objeto (según la pregunta original) con nombres de propiedad simples es iterable.
kingPuppy
1
Funciona en Chrome, este es ES6, necesitarás Babel o algún transpilador ES6 actualmente. En el futuro, se espera que todos los navegadores admitan esta sintaxis.
kingPuppy
89

Recorra las propiedades del primer objeto y asígnelas al segundo objeto, así:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

El for- inbucle no es suficiente; lo que necesita hasOwnProperty. Consulte http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop para obtener una explicación detallada de por qué.

Ben Lee
fuente
@RobW, no pensé que el OP está usando referenceen el sentido técnico. Creo que solo quiere decir lenguaje natural "refiriéndose a".
Ben Lee
1
@RobW: El OP realmente dijo "copiar".
TJ Crowder
49

Jugar al nigromante aquí, porque ES5 nos trajo Object.keys(), con potencial para salvarnos de todos estos .hasOwnProperty()controles.

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

O, envolviéndolo en una función ("copia" limitada de lodash _.assign()):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys()es un método relativamente nuevo, sobre todo: no está disponible en IE <9. Lo mismo ocurre con el .forEach()método de matriz, que utilicé en lugar del forbucle regular .

Afortunadamente, hay es5-shim disponible para estos navegadores antiguos, que rellenará muchas funciones de ES5 (incluidas esas dos).

(Estoy a favor de los polyfills en lugar de evitar el uso de nuevas y geniales funciones de lenguaje).

bardzusny
fuente
De repente, 2 votos negativos de la nada. Escasas posibilidades de que esos tipos lean este comentario: ¿cuál es la razón real para ellos? ¿Algo que sugiera cambiar / mejorar en mi respuesta?
bardzusny
1
Esto definitivamente merece llegar a la cima, así como el inicializador de propagación de objetos más abajo (ES6): ¡esto se ve aún más limpio con las funciones de flecha!
mjohnsonengr
12

Necro'ing para que las personas puedan encontrar un método de copia profunda con hasOwnProperty y verificación de objeto real:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};
Nijikokun
fuente
Tenga en cuenta que esto no copia en profundidad las matrices ni los objetos de función (pero sí copia en profundidad todos los demás tipos de objetos).
Matt Browne
1
Sí, si desea copiar en profundidad las matrices, simplemente modifique la verificación de tipo para incluirla'[object Array]'
Nijikokun
12

Se puede usar Object.assign para combinar objetos. Combinará y anulará la propiedad común de derecha a izquierda, es decir, la misma propiedad en la izquierda será anulada por la derecha.

Y es importante suministrar un objeto vacío en el primero para evitar la mutación de los objetos fuente. Los objetos de origen deben dejarse limpios ya que Object.assign()por sí solo devuelve un nuevo objeto.

¡Espero que esto ayude!

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)

Pranesh Ravi
fuente
pero ¿y si quieres que mute el primer objeto? ¿Tiene el objeto A y el objeto B y desea que mute el objeto A para que todas las propiedades sean iguales a lo que son en el objeto B? ¿Harías Object.assign (A, B)?
TKoL
Lamentablemente no es compatible con IE, Android WebView, Android Opera de acuerdo con esa página de la red de desarrolladores de Mozilla.
Yetti99
6

Mejora de la idea kingPuppy y la idea OP (copia superficial): solo agrego 3 puntos al "ejemplo" OP :)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

Kamil Kiełczewski
fuente
4

Esto debería funcionar, probado aquí .

var secondObject = {
    firstObject: JSON.parse(JSON.stringify(firstObject)),
    key3 : 'value3',
    key4 : 'value4'
};

Nota : esto no copiará los métodos de la firstObject
Nota 2 : para usar en navegadores antiguos, necesitará un analizador json.
Nota 3 : la asignación por referencia es una opción viable, especialmente si firstObjectcontiene métodos. Ajustó el ejemplo jsfiddle dado en consecuencia

KooiInc
fuente
3

Desafortunadamente, no puede poner una referencia a una variable en un objeto como ese. Sin embargo, puede realizar una función que copie los valores del objeto en otro objeto.

function extend( obj1, obj2 ) {
    for ( var i in obj2 ) {
        obj1[i] = obj2[i];
    }
    return obj1;
}

var firstObject = {
    key1: "value1",
    key2: "value2"
};

var secondObject = extend({
    key3: "value3",
    key4: "value4"
}, firstObject );
Será
fuente
Esto también copiará las propiedades nativas. ¿Y qué hay de las propiedades que son los propios Objetos?
KooiInc
1

Si desea tomar solo las propiedades que existen en el segundo objeto, puede usar Object.keyspara tomar las propiedades del primer objeto, puede hacer dos métodos:

A.) map para asignar las propiedades del primer objeto al segundo objeto usando efectos secundarios:

var a = {a:100, b:9000, c:300};
var b = {b:-1};

Object.keys(a).map(function(key, index) {
    if (typeof b[key] !== 'undefined') {
        console.log(key);
        b[key] = a[key];    
    }
});

B.) o reducepara crear un nuevo objeto y asignarlo al segundo objeto. Tenga en cuenta que este método reemplaza otras propiedades que el segundo objeto podría tener antes de las que no coincidían con el primer objeto:

var a = {a:100, b:9000, c:300};
var b = {b:-1, d:-1}; // d will be gone

b = Object.keys(a).reduce(function(result, current) {
    if (typeof b[current] !== 'undefined') {
        result[current] = a[current];   
    }
    return result;
}, {});
bestia
fuente
1

Use la notación de propagación de propiedad. Se agregó en ES2018 (la distribución para matrices / iterables era anterior, ES2015), {... firstObject} extiende todas las propiedades enumerables como propiedades discretas.

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }
Anthony Awuley
fuente
Puede por favor dar algún contexto de su respuesta y por qué es la solución de la cuestión que nos ocupa
Tamir Klein
0

Prefiero usar firstObject como prototipo de secondObject y agregar el descriptor de propiedad:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3", writable: true, configurable: true, enumerable: true},
      key4: {value: "value4", writable: true, configurable: true, enumerable: true}
      });

Ciertamente no es una línea, pero te da más control. Si está interesado en los descriptores de propiedades, le sugiero que lea este artículo: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 y la página MDN https: //developer.mozilla. org / es-es / docs / Web / JavaScript / Reference / Global_Objects / Object / create

También puede simplemente asignar valores y omitir los descriptores y hacerlo un poco más corto:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3"}
      key4: {value: "value4"}
  });

Compatibilidad: ECMAScript 5, entonces IE9 +

Ahmet Cetin
fuente
0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

var secondObject = {
     key3: "value3",
     key4: "value4"
     copy: function(firstObject){
           this.key1 = firstObject.key1;
           this.key2 = firstObject.key2;
     }
 };

El uso del siguiente método copiará las propiedades

secondObject.copy(firstObject)

Soy muy nuevo en javascript, pero encontré que esto funciona. Un poco demasiado largo, supongo, pero funciona.

Sindhu Tirth
fuente