javascript ecmascript-6 ecmascript-5 spread-syntax

Uso de parámetros de reposo y operador de propagación en javascript



ecmascript-6 ecmascript-5 (5)

¿Cuál es el uso del parámetro de descanso que se agregará en ECMAScript 6?

Por ejemplo, en ECMAScript 5 puede hacer lo siguiente para obtener una matriz de parámetros a partir del segundo elemento:

// ES 5 store(''Joe'', ''money''); store(''Jane'', ''letters'', ''certificates''); function store(name) { var items = [].slice.call(arguments, 1); //[''money''] in first case items.forEach(function (item) { vault.customer[name].push(item); }); }

y eso será equivalente al siguiente código en ECMAScript 6:

// ES 6 store(''Joe'', ''money''); store(''Jane'', ''letters'', ''certificates''); function store(name, ...items) { items.forEach(function (item) { vault.customer[name].push(items) }); }

¿La diferencia entre ellos es solo la sintaxis o hay un problema de rendimiento?

También para operador de propagación (...)

//in ecmascript5 var max = Math.max.apply(null, [14, 3, 77]); //but in ecmascript6 var max = Math.max(...[14, 3, 77]);

¿Es solo un cambio de sintaxis o un problema de rendimiento?


¿La diferencia entre ellos es solo la sintaxis o hay un problema de rendimiento?

Ambos, y más ...

Parámetros de descanso:

  1. Son un idioma conocido en otros idiomas (Ruby, Python).
  2. Son más fáciles de leer y mantener (frente a slice ).
  3. Son más fáciles de entender para los principiantes.
  4. Puede (y probablemente) dará como resultado un mejor rendimiento , ya que los motores pueden optimizar.
  5. Son herramientas más amigables , ya que pueden ser analizadas estáticamente.

Además de la respuesta de @kangax, elaboraría que el rendimiento y la corrección son problemáticos muchas veces que se invoca el objeto de arguments . Si pasa el objeto de arguments a otra función, le otorga el derecho de modificar las variables locales correspondientes en su alcance .

function foo(arg) { bar(arguments); return arg; } function bar(args) { args[0] = 20; } foo(10) // 20

La existencia de esta función invalida el razonamiento local dentro de una función, lo que dificulta la optimización de JIT e introduce ciertos riesgos de seguridad. Los programas diseñados para la velocidad deben solucionar este problema con un código de repetición mucho más elaborado que el lenguaje Array.prototype.slice.call(arguments) , y en contextos de seguridad, el paso de los arguments debe ser estrictamente rechazado.

Eliminar la necesidad de usar el objeto de arguments para extraer argumentos variadic es una de las muchas ventajas de la nueva sintaxis.


Creo que las principales diferencias en el parámetro de reposo son:

  • Los argumentos en los argumentos de ECMA5 son como una matriz, no una matriz, por lo que los métodos normales de la matriz no están disponibles, pero en los argumentos de ECMA6 es una matriz.
  • Creo que crear una matriz de elementos en el ejemplo del código ECMA5 hará que el código sea un poco más lento porque se crea una instancia de la nueva matriz.

En su ejemplo dado, usted pasa directamente el objeto literal. Si bien aún es semántico, parece análogo a la aplicación del operador de propagación. En mi opinión, el valor del operador de propagación se hace evidente al enumerar cada parámetro deterioraría la legibilidad del código (y la capacidad de mantenimiento, al reemplazar los métodos tradicionales de empuje, empalme, concat).

Con operador extendido

let nums = [1.25,5.44,7.15,4.22,6.18,3.11]; function add(a, b, ...nums){ let sum = parseInt(a + b); nums.forEach(function(num) { sum += num; }) return parseInt(sum); } console.log(add(1, 2, ...nums)); //30

Demostración de ES6Fiddle (compilada por traceur-compiler )

Operador sin propagación

var nums = [1.25,5.44,7.15,4.22,6.18,3.11]; function add(a, b, nums){ var sum = parseInt(a + b); nums.forEach(function(num) { sum += num; }) return parseInt(sum); } console.log(add(1, 2, nums)); //30

Demostración de JSFiddle

Para terminar, no creo que el uso del operador de propagación mejore o impida el rendimiento, sin embargo, ofrece una mejor legibilidad del código y posiblemente también la capacidad de mantenimiento. Lamentablemente, ES6 aún no se ha implementado ampliamente, y especularé con firmeza que tomará algún tiempo para que se produzca el soporte del navegador.

Dato curioso : PHP 5.6 introduce una funcionalidad similar con sus funciones variables que harán que func_get_args() redundante.


Un parámetro de rest recopilará parámetros individuales en una matriz cuando use los puntos en la definición de un parámetro de función, mientras que el operador de propagación expandirá una matriz en parámetros individuales cuando use los puntos en una function call .

Cuando quiera recopilar parámetros individuales en una matriz, debe usar el operador rest en su función param definición.

let sum = (...numbers) => { let result = 0; numbers.forEach(function(n){ result += n; }); return result; }; console.log(sum(1,2,3));

Tratar con el objeto de arguments dentro de la función anidada se vuelve realmente difícil, vamos a visitar la siguiente situación donde nuestra función interna necesita acceso al objeto de arguments pasado.

Si nuestra inner function filterNumbers necesita acceso a los argumentos, debe almacenarse en una variable antes de continuarla, ya que cada función tiene su propio objeto de arguments , que es un objeto similar a una matriz.

function sumOnlyNumbers() { var args = arguments; var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return Array.prototype.filter.call(args, element => typeof element === ''number'' ); } } sumOnlyNumbers(1, ''Hello'', 5, false);

El enfoque funciona, pero es demasiado detallado. var args = arguments se pueden omitir y Array.prototype.filter.call(args) se puede transformar en args.filter() utilizando un parámetro de rest .

function sumOnlyNumbers(...args) { var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return args.filter(element => typeof element === ''number''); } } sumOnlyNumbers(1, ''Hello'', 5, false); // => 6

Cuando quiera expandir una matriz a parámetros individuales, debe usar el operador de propagación en su llamada de función.

let sum = (a,b,c) => { return a + b + c; }; console.log(sum(...[1,2,3]));

En el código anterior, el operador de propagación “spread” la matriz de tres valores a través de los parameters a, b, and c . El operador de spread también puede expandir una matriz para crear elementos individuales en un literal de array .

var a = [4, 5, 6]; var b = [1, 2, 3, ...a, 7, 8, 9] console.log(b);

Invocación de la función mejorada en ES6

ES5 proporciona el método .apply() en el objeto de función para resolver esto. Desafortunadamente esta técnica tiene 3 problemas:

  • Es necesario indicar manualmente el contexto de la invocación de la función.
  • No es posible usar en una invocación de constructor
  • Una solución más corta es más preferible

Parece irrelevante indicar en .apply() segunda vez que los países del contexto lo hacen más detallado.

let countries = [''India'', ''USA'']; let otherCountries = [''China'', ''Japan'']; countries.push.apply(countries, otherCountries); console.log(countries); // => [''India'', ''USA'', ''China'', ''Japan'']

El operador de spread llena los argumentos de invocación de la function con valores de una array . Mejoremos la muestra anterior con un operador de propagación:

let countries = [''India'', ''USA'']; let otherCountries = [''China'', ''Japan'']; countries.push(...otherCountries); console.log(countries); // => [''Moldova'', ''Ukraine'', ''USA'', ''Japan'']

Spread operador de Spread configura los argumentos de invocación del constructor desde una matriz, que es un poco complicado y difícil directamente cuando se usa .apply() .

class Actor { constructor(name, country) { this.name = name; this.country = country; } getDescription() { return `${this.name} leads ${this.country}`; } } var details = [''RajiniKanth the Great'', ''India'']; var Alexander = new Actor(...details); console.log(Alexander.getDescription()); // => ''RajiniKanth the Great leads India''

Además, puede combinar múltiples operadores de spread y argumentos regulares en la misma invocación. El siguiente ejemplo es eliminar de una matriz elementos existentes, luego agrega otra matriz y un elemento:

var numbers = [1, 2]; var evenNumbers = [4, 8]; const zero = 0; numbers.splice(0, 2, ...evenNumbers, zero); console.log(numbers); // => [4, 8, 0]

Clone una instancia de matriz:

var words = [''Hi'', ''Hello'', ''Good day'']; var otherWords = [...words]; console.log(otherWords); // => [''Hi'', ''Hello'', ''Good day''] console.log(otherWords === words); // => false

otherWords es una versión clónica de la matriz de palabras. Tenga en cuenta que la clonación se produce solo en la propia matriz, pero no en los elementos contenidos (es decir, no es un clon profundo).

Referencias: https://rainsoft.io/how-three-dots-changed-javascript/