Usando la variable _ (guión bajo) con funciones de flecha en ES6 / Typecript

119

Me encontré con esta construcción en un ejemplo angular y me pregunto por qué se elige esto:

_ => console.log('Not using any parameters');

Entiendo que la variable _ significa que no me importa / no se usa, pero dado que es la única variable, ¿hay alguna razón para preferir el uso de _ sobre:

() => console.log('Not using any parameters');

Seguramente esto no puede ser un carácter menos para escribir. La sintaxis () transmite mejor la intención en mi opinión y también es más específica del tipo porque, de lo contrario, creo que el primer ejemplo debería haberse visto así:

(_: any) => console.log('Not using any parameters');

En caso de que importe, este fue el contexto en el que se utilizó:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}
Detener
fuente
1
¿Cómo puede preocuparse por escribir o especificidad de tipo para un parámetro que nunca se utiliza?
3
Soy un desarrollador de C ++ de oficio, así que supongo que siempre me preocupa la especificidad del tipo :-).
Detener
6
Personalmente, el patrón _ => reduce el número de corchetes, lo que facilita la lectura: doStuff (). Then (() => action ()) vs doStuff (). Then (_ => action ()).
Damien Golding

Respuestas:

93

La razón por la que se puede usar este estilo (y posiblemente la razón por la que se usó aquí) es que _es un carácter más corto que ().

Los paréntesis opcionales caen en el mismo problema de estilo que los corchetes opcionales . Esto es una cuestión de gusto y estilo de código en su mayor parte, pero aquí se favorece la verbosidad debido a la coherencia.

Si bien las funciones de flecha permiten un solo parámetro sin paréntesis, es inconsistente con cero, solo desestructurado, solo descanso y múltiples parámetros:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

Aunque se corrigió elis declared but never used error en TypeScript 2.0 para los parámetros subrayados, _también puede activar una unused variable/parameteradvertencia de un linter o IDE. Este es un argumento considerable en contra de hacer esto.

_se puede usar convencionalmente para parámetros ignorados (como la otra respuesta ya se explicó). Si bien esto puede considerarse aceptable, este hábito puede resultar en un conflicto con el _espacio de nombres de subrayado / Lodash, también parece confuso cuando hay varios parámetros ignorados. Por esta razón, es beneficioso tener los parámetros subrayados correctamente nombrados (admitidos en TS 2.0), también ahorra tiempo en descubrir la firma de la función y por qué los parámetros se marcan como ignorados (esto desafía el propósito del _parámetro como un atajo):

let fn = (param1, _unusedParam2, param3) => { ... };

Por las razones enumeradas anteriormente, personalmente consideraría el _ => { ... }estilo del código como un mal tono que debería evitarse.

Matraz Estus
fuente
1
Es un carácter más corto, pero es la misma cantidad de pulsaciones de teclas para la mayoría de los IDE, ya que al pulsar (normalmente viene con un ). Personalmente prefiero usar ppara el parámetro, también me pregunto si tiene algún problema de rendimiento
Mojimi
68

La ()sintaxis transmite la intención mejor en mi humilde opinión y también es más específica del tipo

No exactamente. ()dice que la función no espera ningún argumento, no declara ningún parámetro. La función .lengthes 0.

Si lo usa _, indica explícitamente que a la función se le pasará un argumento, pero que no le importa. La función .lengthserá 1, lo que puede ser importante en algunos marcos.

Entonces, desde una perspectiva de tipografía, podría ser algo más preciso (especialmente cuando no lo escribe con anypero, digamos _: Event). Y como dijiste, es un carácter menos para escribir, lo que también es más fácil de alcanzar en algunos teclados.

Bergi
fuente
6
Mi primer pensamiento fue que _ hace que sea obvio por convención que no hay argumentos a considerar cuando se trata de entender la función. El uso de () lo hace explícito, no es necesario escanear el código para un posible uso de _ (que violaría la convención). Pero me abrió los ojos para considerar también el valor de documentar que se pasa un valor a la función, que de otro modo no siempre sería obvio.
Detener
Me acabo de dar cuenta de que mi código está lleno de _variables de función de flecha s no utilizadas , me pregunto si hay alguna diferencia de rendimiento en comparación con el uso()
Mojimi
24

Supongo que _ =>se acaba de usar () =>porque _es común en otros lenguajes donde no se permite simplemente omitir parámetros como en JS.

_ es popular en Go y también se usa en Dart para indicar que se ignora un parámetro y probablemente otros que no conozco.

Günter Zöchbauer
fuente
4
Python también sigue esta convención, creo.
Jaime RGP
7
Este uso de _presumiblemente fue tomado de lenguajes funcionales como ML y Haskell, donde es anterior a la invención de Python (por no hablar de Go, Dart o TypeScript).
ruakh
1
también Ruby hace eso ( po-ru.com/diary/rubys-magic-underscore ) y F # también (y otros idiomas influenciados por la familia ML)
Mariusz Pawelski
A Scala le encanta el subrayado ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). ¿Qué más idiomas tomó después de lo que hace Scala con tipos anónimos con guión bajo?
Sam
Supongo que Scala también lo tomó de algún otro idioma. Casi no hay nada en los lenguajes de programación que no existiera ya en los años 70: D En su mayoría, solo nuevas formas de combinar las cosas.
Günter Zöchbauer
11

Es posible distinguir entre los dos usos, y algunos marcos lo utilizan para representar diferentes tipos de devoluciones de llamada. Por ejemplo, creo que el marco expreso de nodos usa esto para distinguir entre tipos de middleware, por ejemplo, los controladores de errores usan tres argumentos, mientras que el enrutamiento usa dos.

Dicha diferenciación puede parecerse al ejemplo siguiente:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);

Michael Anderson
fuente
1
Esto se basa en la respuesta de Bergi, pero pensé que agregar un ejemplo era un poco más de edición de lo que estaba feliz de hacer en la publicación de otra persona.
Michael Anderson
0

Cuando escribí la publicación, tenía la impresión de que _era la única forma de crear funciones de flecha sin ellas (), lo que me llevó a creer que el uso _podría tener algunas ventajas menores, pero estaba equivocado. @Halt ha confirmado en los comentarios que se comporta como otras variables, no es una construcción de lenguaje especial.


Quiero mencionar una cosa más de la que me di cuenta acerca de estas funciones de flecha de subrayado mientras me probaba a mí mismo que no encontré mencionado en ninguna parte. Usted puede utilizar el subrayado en la función como un parámetro , aunque este uso probablemente no se pretende ya que se supone que representa un parámetro no utilizado. Para mayor claridad, realmente no recomendaría usarlo de esta manera. pero puede ser útil saber para cosas como codegolf , desafíos donde escribes el código más corto (resulta que puedes usar cualquier carácter sin él ()). Podría imaginar algunos casos de uso reales en los que las bibliotecas usan esto y usted necesita usarlo incluso si no tenían la intención de esa funcionalidad.

Ejemplo:

// simple number doubling function
f = _=> {
    _ = _ * 2;
    return _;
}

console.log(f(2)); // returns 4
console.log(f(10)); // returns 20

Probado con la consola Chrome, versión 76.0.3809.132 (compilación oficial) (64 bits)

Matsyir
fuente
1
El guión bajo '_' es un nombre de variable legal y no una construcción de lenguaje especial, solo se le da un significado especial por convención. Las advertencias de Linter sobre parámetros no utilizados se pueden silenciar mediante el prefijo de subrayado. Supongo que _ por sí solo es la forma más corta de decir no utilizado.
Detener
@Halt Gracias por la aclaración, es bueno saberlo con seguridad. De hecho, no me di cuenta de que podía hacer funciones de flecha sin ()antes de hacer esta publicación, pensé que _era la única forma de hacerlo, por eso decidí señalar esto. Con esto en mente, resulta que no es nada especial para usar incluso para jugar al golf, ya que podría usar un personaje normal. Es mejor usarlo simplemente para seguir convenciones, como dijiste.
Matsyir