ES6 en Detalle: Parámetros restantes y por defecto

29 septiembre, 2015 4:14 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks.

El artículo de hoy es acerca de dos funciones que hacen la sintaxis de JavaScript más expresiva: parámetros restantes y parámetros por defecto.

Parámetros restantes

Una necesidad común cuando se crean APIs es una función variádica, una función que acepta cualquier cantidad de argumentos. Por ejemplo, el método String.prototype.concat toma cualquier número de hileras como argumento. Con los parámetros restantes, el ES6 provee una nueva forma de escribir funciones variádicas.

Para demostrar, vamos a escribir una función variádica simple containsALL que chequea cuando una cadena contiene un número de sub-cadenas. Por ejemplo, containsALL(“banana”,”b”,”nan”) retornaría true, y containsALL(“banana”,”c”,”nan”) retornaría false.

Aquí está como tradicionalmente implementamos esta función.

function containsAll(haystack) {
  for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

Esta implementación usa el objeto mágico arguments, algo parecido a un arreglo que contiene los parámetros que serán usados por la función. Este código ciertamente hace lo que queremos que haga. Pero es poco óptimo al momento de leerlo. La lista de parámetros de la función solo contiene haystack, así que es imposible decir al momento que la función toma múltiples argumentos. Adicionalmente, debemos ser cautelosos para comenzar a iterar por arguments en el índice 1, y no en 0, ya que arguments[0] corresponde al argumento haystack. Si queremos agregar otro parámetro antes o después de haystack, necesitaríamos recordar actualizar el ciclo for. Los parámetros restantes manejan ambos problemas. Aquí está una implementación natural del ES6 utilizando parámetros restantes:

function containsAll(haystack, ...needles) {
  for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

Esta versión de la función tiene el mismo comportamiento que la primera, pero ésta contiene la sintaxis especial ...needles. Vamos a ver cómo llamar a esta función trabaja para la invocación de containsAll(“banana”,”b”,”nan”). El argumento haystack es asignado como es normal con el primer parámetro “banana”. La elipsis (los tres puntos “…”) antes del needles, indica que es un parámetro restante. Todos los otros parámetros pasados son colocados en un arreglo, y asignados a la variable needles. Para nuestro ejemplo, needles corresponde a [“b”,”nan”]. La ejecución de la función continua normalmente (nota que hemos usado el ciclo for-of de ES6 ).

Solo el último parámetro de una función puede ser marcado como un parámetro restante. Cuando lo llamamos, los parámetros antes del parámetro restante se asignan como es usual. Cualquier argumento “extra” se coloca en un arreglo, el cual se asigna al parámetro restante. Si no hay argumentos extras, el parámetro restante simplemente es un arreglo vacío; el parámetro restante nunca va a ser undefined.

Parámetros por defecto

Es común que una función no necesite llenar todos los parámetros para funcionar. Y hay valores por defecto sensibles que pueden ser usados para los parámetros que no son pasados. JavaScript siempre ha tenido una forma inflexible para los parámetros por defecto; los parámetros que no tienen valor son pasados como undefined. ES6 introduce una forma para especificar valores por defecto para los parámetros.

Aquí hay un ejemplo (los comillas inclinadas representan una hilera plantilla, lo cual discutimos en otro artículo).

function animalSentence(animals2="tigres", animals3="osos") {
    return `¡Leones y ${animals2} y ${animals3}! ¡Vaya!`;
}

Para cada parámetro, la parte después del = es una expresión especificando el valor por defecto de un parámetro, si no se pasan por la función. Así que animalSentence() retornara “¡Leones y tigres y osos! ¡Vaya!”, animalSentence(“elefantes”) retornara “¡Leones y elefantes y osos! ¡Vaya!” y animalsSentence(“elefantes”,”ballenas”) retornará “¡Leones y elefantes y ballenas! ¡Vaya!”.

Existen varias sutilezas relacionadas con los parámetros por defecto:

  • A diferencia de Python, las expresiones por defecto son evaluadas cuando se llama la función, de izquierda a derecha. Esto quiere decir que las expresiones por defecto pueden usar valores de parámetros anteriormente llenados. Por ejemplo, podemos hacer nuestra función de frases de animales más bonita así:
    function animalSentenceFancy(animals2="tigres",
        animals3=(animals2 == "osos") ? "leones marinos" : "osos")
    {
        return `¡Leones y ${animals2} y ${animals3}! ¡Vaya!`;
    }

    Entonces, animalSentences(“osos”) retornara, “¡Leones y osos y leones marinos! ¡Vaya!”.

  • Pasar undefined es considerado equivalente a no pasar nada. Por lo tanto animalSentence(undefined, “unicornio”) retornara, “¡Leones y tigres y unicornios! ¡Vaya!”.
  • Un parámetro sin un valor por defecto explícito tiene un valor por defecto undefined, así que
    function miFuncion(a=42, b) {…}

    es permitido y equivalente a

    function miFuncion(a=42,b=undefined){...}

Acabando con arguments

Ahora hemos visto que los parámetros restantes y por defecto pueden reemplazar el uso del objeto arguments, y que remover arguments usualmente hace el código más legible. En adición al daño a la legibilidad, la magia del objeto arguments notoriamente causa dolores de cabeza para optimizar las máquinas virtuales de JavaScript.

Se espera que los parámetros restantes y por defecto puedan reemplazar completamente a arguments. Como primer paso a esto, las funciones que usan parámetros restantes y por defecto tienen prohibido usar el objeto arguments. El soporte para arguments no será removida pronto, o tal vez nunca, pero es preferiblemente evitar usar arguments al usar parámetros restantes y por defecto cuando sea posible.

Soporte de navegadores

Firefox ha tenido soporte para parámetros restantes y por defecto desde la versión 15.

Desafortunadamente, nadie más ha lanzado soporte para los parámetros restantes y por defecto aún. V8 recientemente lanzó un soporte experimental para los parámetros restantes, y hay un issue abierto para implementar parámetros por defecto. JSC también tiene issues abiertos para los parámetros restantes y por defecto.

Los compiladores Babel y Traceur ambos tienen soporte para parámetros por defecto, así que es posible comenzar a usarlos hoy mismo.

Conclusión

A pesar de que técnicamente no introducen nuevos comportamientos, los parámetros restantes y por defecto pueden hacer algunas declaraciones de funciones más expresivas y legibles.

Nota: muchas gracias a Benjamín Peterson por implementar estas características en Firefox, por todas sus contribuciones al proyecto y claro por el post de esta semana.

The following two tabs change content below.
Si, mi biografia esta vacia. 🙂

Compartir artículo:

Empezar la discusión en foro.mozilla-hispano.org

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa