javascript - ecmascript 6 support
Objeto extendido contra Object.assign (9)
Digamos que tengo una variable de
options
y quiero establecer un valor predeterminado.
¿Cuál es el beneficio / inconveniente de estas dos alternativas?
Usar propagación de objetos
options = {...optionsDefault, ...options};
O usando Object.assign
options = Object.assign({}, optionsDefault, options);
Este es el commit que me hizo preguntarme.
Como otros han mencionado, en este momento de la escritura,
Object.assign()
requiere un polyfill y una propagación de objetos
...
requiere un poco de transpiling (y quizás un polyfill también) para funcionar.
Considera este código:
// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: ''Hello you!'' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: ''Hello you!'' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);
Ambos producen la misma salida.
Aquí está la salida de Babel, a ES5:
var objAss = { message: ''Hello you!'' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var objSpread = { message: ''Hello you!'' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);
Este es mi entendimiento hasta ahora.
Object.assign()
está realmente estandarizado, mientras que como objeto extendido
...
todavía no lo está.
El único problema es el soporte del navegador para el primero y en el futuro, el segundo también.
Espero que esto ayude.
Creo que una gran diferencia entre el operador de propagación y
Object.assign
que no parece mencionarse en las respuestas actuales es que el operador de propagación no mantendrá el prototipo intacto.
Si desea agregar propiedades a un objeto y no desea cambiar de qué es una instancia, tendrá que usar
Object.assign
.
El siguiente ejemplo debería demostrar esto:
const error = new Error();
console.error instanceof Error; // true
const errorExtendedUsingSpread = {
...error,
...{
someValue: true
}
};
errorExtendedUsingSpread instanceof Error; // false
const errorExtendedUsingAssign = Object.assign(error, {
someValue: true
});
errorExtendedUsingAssign instanceof Error; // true
El objeto de referencia rest / spread se finaliza en ECMAScript 2018 como una etapa 4. La propuesta se puede encontrar here .
En su mayor parte, el restablecimiento y la propagación de objetos funcionan de la misma manera, la diferencia clave es que la propagación define las propiedades, mientras que Object.assign () las establece . Esto significa que Object.assign () activa los establecedores.
Vale la pena recordar que, aparte de esto, el objeto rest / spread 1: 1 se asigna a Object.assign () y actúa de manera diferente a la matriz (iterable) spread. Por ejemplo, cuando se extiende una matriz, los valores nulos se extienden. Sin embargo, el uso de objetos con valores nulos se extiende silenciosamente a nada.
Ejemplo de dispersión de matriz (Iterable)
const x = [1, 2, null , 3];
const y = [...x, 4, 5];
console.log(y); // [1, 2, null, 3, 4, 5];
Ejemplo de dispersión de objetos
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
console.log(z); //{a: 1, b: 2}
Esto es coherente con cómo funcionaría Object.assign (), ambos excluyen silenciosamente el valor nulo sin error.
const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
El operador de propagación de objetos (...) no funciona en los navegadores, porque todavía no forma parte de ninguna especificación de ES, solo una propuesta. La única opción es compilarlo con Babel (o algo similar).
Como puede ver, es solo azúcar sintáctico sobre Object.assign ({}).
Hasta donde puedo ver, estas son las diferencias importantes.
- Object.assign funciona en la mayoría de los navegadores (sin compilar)
-
...
para los objetos no está estandarizado -
...
te protege de mutar accidentalmente el objeto -
...
rellenará Object.assign en los navegadores sin él -
...
necesita menos código para expresar la misma idea
Esto ahora es parte de ES6, por lo tanto, está estandarizado y también está documentado en MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
Es muy conveniente de usar y tiene mucho sentido junto con la desestructuración de objetos.
La ventaja restante que se menciona anteriormente es la capacidad dinámica de Object.assign (), sin embargo, esto es tan fácil como distribuir la matriz dentro de un objeto literal. En la salida compilada de babel, usa exactamente lo que se demuestra con Object.assign ()
Por lo tanto, la respuesta correcta sería usar la distribución de objetos, ya que ahora está estandarizada, se usa ampliamente (ver react, redux, etc.), es fácil de usar y tiene todas las características de Object.assign ()
Esto no es necesariamente exhaustivo.
Sintaxis extendida
options = {...optionsDefault, ...options};
Ventajas:
-
Si crea código para su ejecución en entornos sin soporte nativo, puede compilar esta sintaxis (en lugar de usar un polyfill). (Con Babel, por ejemplo).
-
Menos detallado
Desventajas
-
Cuando esta respuesta se escribió originalmente, se trataba de una proposal , no estandarizada. Cuando use propuestas, considere lo que haría si escribe código con él ahora y no se estandariza o cambia a medida que avanza hacia la estandarización. Desde entonces, esto se ha estandarizado en ES2018.
-
Literal, no dinámico.
Object.assign()
options = Object.assign({}, optionsDefault, options);
Ventajas:
-
Estandarizado.
-
Dinámica. Ejemplo:
var sources = [{a: "A"}, {b: "B"}, {c: "C"}]; options = Object.assign.apply(Object, [{}].concat(sources)); // or options = Object.assign({}, ...sources);
Desventajas
- Más detallado.
- Si el código de autoría se ejecuta en entornos sin compatibilidad nativa, debe rellenarlo.
Este es el compromiso que me hizo preguntarme.
Eso no está directamente relacionado con lo que estás preguntando.
Ese código no estaba usando
Object.assign()
, estaba usando un código de usuario (
object-assign
) que hace lo mismo.
Parece que compilan ese código con Babel (y lo agrupan con Webpack), que es de lo que estaba hablando: la sintaxis que puedes compilar.
Aparentemente prefirieron eso a tener que incluir
object-assign
como una dependencia que iría en su construcción.
Me gustaría resumir el estado de la función ES de "fusión de objetos distribuidos", en navegadores y en el ecosistema a través de herramientas.
Especulación
- here
- Esta característica del lenguaje es una propuesta de etapa 4 , lo que significa que se ha fusionado con la especificación del lenguaje ES, pero aún no se ha implementado ampliamente.
Navegadores: en Chrome, en SF, Firefox pronto (ver 60, IIUC)
- La compatibilidad del navegador para las "propiedades de propagación" incluidas en Chrome 60 , incluido este escenario.
- El soporte para este escenario NO funciona en Firefox actual (59), pero sí funciona en mi Firefox Developer Edition. Así que creo que se enviará en Firefox 60.
- Safari: no probado, pero Kangax dice que funciona en Desktop Safari 11.1, pero no en SF 11
- Safari de iOS: no probado, pero Kangax dice que funciona en iOS 11.3, pero no en iOS 11
- aún no en Edge
Herramientas: Nodo 8.7, TS 2.1
- NodeJS es compatible desde 8.7 (a través de Kangax). Confirmado en 9.8 cuando probé localmente.
- TypeScript lo ha soportado desde 2.1 , la actual es 2.8
Campo de golf
Muestra de código (funciona como prueba de compatibilidad)
var x = { a: 1, b: 2 };
var y = { c: 3, d: 4, a: 5 };
var z = {...x, ...y};
console.log(z); // { a: 5, b: 2, c: 3, d: 4 }
Nuevamente: al momento de escribir este ejemplo, funciona sin transpilación en Chrome (60+), Firefox Developer Edition (versión preliminar de Firefox 60) y Node (8.7+).
¿Por qué responder?
Estoy escribiendo esto 2.5 años después de la pregunta original. Pero tenía la misma pregunta, y aquí es donde me envió Google. Soy un esclavo de la misión de SO de mejorar la larga cola.
Dado que esta es una expansión de la sintaxis de "dispersión de matriz", encontré que es muy difícil para google y difícil de encontrar en las tablas de compatibilidad. Lo más cercano que pude encontrar es Kangax "spread de propiedad" , pero esa prueba no tiene dos spreads en la misma expresión (no una fusión). Además, el nombre en las páginas de propuestas / borradores / estado del navegador todos usan "propagación de propiedad", pero me parece que fue un "primer director" al que llegó la comunidad después de las propuestas para usar la sintaxis de propagación para "fusión de objetos". (Lo que podría explicar por qué es tan difícil buscar en Google). Así que documento mi hallazgo aquí para que otros puedan ver, actualizar y compilar enlaces sobre esta característica específica. Espero que se ponga de moda. Ayude a difundir la noticia de que aterriza en las especificaciones y en los navegadores.
Por último, habría agregado esta información como comentario, pero no podía editarla sin romper la intención original de los autores. Específicamente, no puedo editar el comentario de @ ChillyPenguin sin que pierda su intención de corregir a @RichardSchulte. Pero años después, Richard resultó tener razón (en mi opinión). Así que escribo esta respuesta en su lugar, con la esperanza de que eventualmente gane fuerza sobre las respuestas antiguas (podría tomar años, pero de eso se trata el efecto de cola larga , después de todo).
NOTA: Spread NO es solo azúcar sintáctico alrededor de Object.assign. Operan de manera muy diferente detrás de escena.
Object.assign aplica setters a un nuevo objeto, Spread no. Además, el objeto debe ser iterable.
Copiar Use esto si necesita el valor del objeto tal como está en este momento, y no desea que ese valor refleje los cambios realizados por otros propietarios del objeto.
Úselo para crear una copia superficial del objeto, una buena práctica para establecer siempre propiedades inmutables para copiar, ya que las versiones mutables se pueden pasar a propiedades inmutables, la copia garantizará que siempre esté tratando con un objeto inmutable
Asignar Asignar es algo opuesto a copiar. Asignar generará un setter que asigna el valor a la variable de instancia directamente, en lugar de copiarlo o retenerlo. Al llamar al captador de una propiedad de asignación, devuelve una referencia a los datos reales.
Otras respuestas son viejas, no se pudo obtener una buena respuesta.
El siguiente ejemplo es para literales de objetos, ayuda a que ambos puedan complementarse entre sí y cómo no pueden complementarse entre sí (por lo tanto, la diferencia):
var obj1 = { a: 1, b: { b1: 1, b2: ''b2value'', b3: ''b3value'' } };
// overwrite parts of b key
var obj2 = {
b: {
...obj1.b,
b1: 2
}
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write(''res2: '', JSON.stringify (res2), ''<br>'');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}} // NOTE: b2,b3 still exists
// overwrite whole of b key
var obj3 = {
b: {
b1: 2
}
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write(''res3: '', JSON.stringify (res3), ''<br>'');
// Output:
// res3: {"a":1,"b":{"b1":2}} // NOTE: b2,b3 values are lost
Varios ejemplos más pequeños aquí, también para array y objeto:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax