Utilizzo della variabile _ (trattino basso) con funzioni freccia in ES6 / Typescript


120

Mi sono imbattuto in questo costrutto in un esempio angolare e mi chiedo perché sia ​​stato scelto:

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

Capisco che la variabile _ significa non importa / non usata ma poiché è l'unica variabile c'è qualche motivo per preferire l'uso di _ rispetto a:

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

Sicuramente questo non può essere di circa un carattere in meno da digitare. La sintassi () trasmette meglio l'intento secondo me ed è anche più specifica per tipo perché altrimenti penso che il primo esempio avrebbe dovuto assomigliare a questo:

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

Nel caso fosse importante, questo era il contesto in cui è stato utilizzato:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}


1
Come puoi preoccuparti della digitazione o della specificità del tipo per un parametro che non viene mai utilizzato?

3
Sono uno sviluppatore C ++ di professione quindi credo di essere sempre preoccupato per la specificità del tipo :-).
Interrompere l'

6
Personalmente, il modello _ => riduce il numero di parentesi rendendone più facile la lettura: doStuff (). Then (() => action ()) vs doStuff (). Quindi (_ => action ()).
Damien Golding

Risposte:


94

Il motivo per cui questo stile può essere utilizzato (e forse perché è stato usato qui) è che _è un carattere più corto di ().

Le parentesi facoltative rientrano nello stesso problema di stile delle parentesi graffe facoltative . Questa è una questione di gusto e stile di codice per la maggior parte, ma la verbosità è favorita qui a causa della coerenza.

Mentre le funzioni freccia consentono un singolo parametro senza parentesi, è incoerente con zero, singola destrutturata, singola pausa e più parametri:

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

Sebbene l' is declared but never usederrore sia stato corretto in TypeScript 2.0 per i parametri sottolineati, _può anche attivare un unused variable/parameteravviso da un linter o da un IDE. Questo è un argomento considerevole contro questa operazione.

_può essere convenzionalmente utilizzato per parametri ignorati (come l'altra risposta già spiegata). Sebbene questo possa essere considerato accettabile, questa abitudine può provocare un conflitto con _lo spazio dei nomi Underscore / Lodash, inoltre sembra confuso quando ci sono più parametri ignorati. Per questo motivo è vantaggioso disporre di parametri sottolineati correttamente denominati (supportati in TS 2.0), inoltre consente di risparmiare tempo nel capire la firma della funzione e il motivo per cui i parametri sono contrassegnati come ignorati (questo sfida lo scopo del _parametro come scorciatoia):

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

Per i motivi sopra elencati, personalmente considererei lo _ => { ... }stile del codice un brutto tono che dovrebbe essere evitato.


1
È un carattere più corto ma è la stessa quantità di pressioni dei tasti per la maggior parte degli IDE, poiché la pressione di (solito viene fornita con un ). Personalmente preferisco usare pper i parametri, mi chiedo anche se ha qualche problema di prestazioni
Mojimi

69

La ()sintassi trasmette meglio l'intento ed è anche più specifica per il tipo

Non esattamente. ()dice che la funzione non si aspetta alcun argomento, non dichiara alcun parametro. La funzione .lengthè 0.

Se lo usi _, afferma esplicitamente che alla funzione verrà passato un argomento, ma che non ti interessa. La funzione .lengthsarà 1, il che potrebbe essere importante in alcuni framework.

Quindi, dal punto di vista del tipo, potrebbe essere una cosa più accurata da fare (specialmente quando non la digiti con anyma, diciamo, _: Event). E come hai detto, è un carattere in meno da digitare, che è anche più facile da raggiungere su alcune tastiere.


6
Il mio primo pensiero è stato che _ rende ovvio solo per convenzione che non ci sono argomenti da considerare quando si cerca di capire la funzione. L'uso di () lo rende esplicito, non c'è bisogno di scansionare il codice per un possibile uso di _ (che violerebbe la convenzione). Ma mi hai aperto gli occhi per considerare anche il valore di documentare che c'è un valore passato alla funzione, che altrimenti non sarebbe sempre evidente.
Fermare l'

Mi sono appena reso conto che il mio codice è pieno di _variabili della funzione freccia inutilizzate , mi chiedo se ci sia qualche differenza di prestazioni rispetto all'utilizzo()
Mojimi

25

Immagino _ =>sia solo usato () =>perché _è comune in altre lingue in cui non è consentito omettere solo parametri come in JS.

_ è popolare in Go ed è utilizzato anche in Dart per indicare che un parametro viene ignorato e probabilmente altri che non conosco.


4
Anche Python segue questa convenzione, credo.
Jaime RGP

7
Questo utilizzo di è _stato presumibilmente preso in prestito da linguaggi funzionali come ML e Haskell, dove precede da tempo l'invenzione di Python (per non parlare di Go, Dart o TypeScript).
ruakh

1
anche Ruby lo fa ( po-ru.com/diary/rubys-magic-underscore ) e anche F # (e altri linguaggi influenzati dalla famiglia ML)
Mariusz Pawelski

Scala ama il carattere di sottolineatura ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). Quali altri linguaggi hanno preso dopo quello che Scala sta facendo con i tipi anonimi con trattino basso.
Sam

Immagino che Scala l'abbia preso anche da qualche altra lingua. Non c'è quasi nulla nei linguaggi di programmazione che non esistesse già negli anni '70: D Per lo più solo nuovi modi per combinare le cose.
Günter Zöchbauer

11

È possibile distinguere tra i due utilizzi e alcuni framework lo utilizzano per rappresentare diversi tipi di callback. Ad esempio, penso che il framework Nodes Express lo utilizzi per distinguere tra i tipi di middleware, ad esempio i gestori di errori utilizzano tre argomenti, mentre il routing ne utilizza due.

Tale differenziazione può essere simile all'esempio seguente:

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);


1
Questo si basa sulla risposta di Bergi, ma ho pensato che aggiungere un esempio fosse un po 'più di editing di quanto fossi felice di fare per qualcun altro.
Michael Anderson

0

Quando ho scritto il post avevo l'impressione che _fosse l'unico modo per creare funzioni freccia senza (), il che mi ha portato a credere che l'utilizzo _potesse avere alcuni piccoli vantaggi, ma mi sbagliavo. @Halt ha confermato nei commenti che si comporta proprio come le altre variabili, non è un costrutto di linguaggio speciale.


Voglio menzionare un'altra cosa che ho realizzato su queste funzioni di sottolineatura della freccia mentre mi provavo che non ho trovato menzionato da nessuna parte. È possibile utilizzare il carattere di sottolineatura nella funzione come parametro , sebbene questo probabilmente non sia un utilizzo previsto poiché dovrebbe rappresentare un parametro inutilizzato. Per chiarezza, non consiglierei davvero di usarlo in questo modo. ma può essere utile sapere per cose come codegolf , sfide in cui scrivi il codice più breve (si scopre che puoi usare qualsiasi carattere senza ()). Potrei immaginare alcuni casi d'uso reali in cui le biblioteche lo usano e devi usarlo anche se non intendevano per quella funzionalità.

Esempio:

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

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

Testato con la console Chrome, versione 76.0.3809.132 (build ufficiale) (64 bit)


1
Il carattere di sottolineatura "_" è un nome di variabile legale e non un costrutto di linguaggio speciale, dato solo un significato speciale per convenzione. Gli avvisi di Linter sui parametri inutilizzati possono essere disattivati ​​utilizzando il prefisso di sottolineatura. Immagino che _ di per sé sia ​​solo il modo più breve per dire inutilizzato.
Interrompi il

@Halt Grazie per la precisazione, buono a sapersi per certo. In realtà non mi ero reso conto che potessi creare funzioni freccia senza ()prima di scrivere questo post, pensavo _fosse l'unico modo per farlo, motivo per cui ho deciso di farlo notare. Con questo in mente si scopre che non è niente di speciale da usare anche per il golf, dal momento che potresti usare solo un personaggio normale. Meglio usato semplicemente per seguire le convenzioni, come hai detto.
Matsyir
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.