Używanie zmiennej _ (podkreślenie) z funkcjami strzałkowymi w ES6 / Typescript

121

Natknąłem się na tę konstrukcję na przykładzie Angulara i zastanawiam się, dlaczego wybrano tę:

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

Rozumiem, że zmienna _ oznacza nie obchodzi / nie jest używana, ale ponieważ jest to jedyna zmienna, istnieje powód, aby preferować użycie _ ponad:

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

Z pewnością nie może to być o jeden znak mniej do wpisania. Składnia () lepiej oddaje intencję moim zdaniem, a także jest bardziej specyficzna dla typu, ponieważ w przeciwnym razie myślę, że pierwszy przykład powinien wyglądać tak:

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

Na wypadek, gdyby miało to znaczenie, był to kontekst, w którym został użyty:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}
Postój
źródło
1
Jak możesz się martwić wpisywaniem lub specyficznością typu dla parametru, który nigdy nie jest używany?
3
Z zawodu jestem programistą C ++, więc myślę, że zawsze martwię się o specyfikę typu :-).
Zatrzymaj
7
Osobiście wzorzec _ => zmniejsza liczbę nawiasów, ułatwiając czytanie: doStuff (). Then (() => action ()) vs doStuff (). Then (_ => action ()).
Damien Golding,

Odpowiedzi:

95

Powodem, dla którego można użyć tego stylu (i prawdopodobnie dlatego został tutaj użyty) jest to, że _jest o jeden znak krótszy niż ().

Opcjonalne nawiasy to ten sam problem ze stylem, co opcjonalne nawiasy klamrowe . Jest to w większości kwestia gustu i stylu kodu, ale w tym przypadku preferowana jest szczegółowość ze względu na spójność.

Podczas gdy funkcje strzałkowe pozwalają na pojedynczy parametr bez nawiasów, jest to niespójne z zerem, pojedynczą zniszczoną, pojedynczą resztą i wieloma parametrami:

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

Chociaż is declared but never usedbłąd został naprawiony w TypeScript 2.0 dla podkreślonych parametrów, _może również wyzwalać unused variable/parameterostrzeżenie z lintera lub IDE. To poważny argument przeciwko temu.

_może być konwencjonalnie używane dla ignorowanych parametrów (jak już wyjaśniono inną odpowiedź). Chociaż można to uznać za akceptowalne, ten nawyk może powodować konflikt z _przestrzenią nazw Underscore / Lodash, a także wygląda myląco, gdy istnieje wiele ignorowanych parametrów. Z tego powodu korzystne jest posiadanie odpowiednio nazwanych podkreślonych parametrów (obsługiwanych w TS 2.0), oszczędza również czas na ustalaniu sygnatury funkcji i dlaczego parametry są oznaczane jako ignorowane (jest to sprzeczne z celem _parametru jako skrótu):

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

Z powodów wymienionych powyżej osobiście _ => { ... }uważałbym styl kodu za zły ton, którego należy unikać.

Estus Flask
źródło
1
Jest o jeden znak krótszy, ale jest to ta sama liczba naciśnięć klawiszy dla większości IDE, ponieważ naciśnięcie (zwykle wiąże się z rozszerzeniem ). Osobiście wolę używać pparametru, zastanawiam się też, czy ma to jakiś problem z wydajnością
Mojimi
69

()Składnia przenosi zamiarem lepszego IMHO, a także jest bardziej specyficzny typ

Nie dokładnie. ()mówi, że funkcja nie oczekuje żadnych argumentów, nie deklaruje żadnych parametrów. Funkcja .lengthto 0.

Jeśli używasz _, wyraźnie stwierdza, że ​​funkcja otrzyma jeden argument, ale nie obchodzi cię to. Funkcja .lengthbędzie miała wartość 1, co może mieć znaczenie w niektórych frameworkach.

Więc z punktu widzenia typu może to być dokładniejsze rozwiązanie (zwłaszcza jeśli nie piszesz tego, anyale powiedzmy _: Event). Jak powiedziałeś, wpisywanie jest o jeden znak mniej, co jest również łatwiejsze do osiągnięcia na niektórych klawiaturach.

Bergi
źródło
6
Moją pierwszą myślą było to, że _ sprawia, że ​​jest oczywiste tylko przez konwencję, że nie ma argumentów do rozważenia przy próbie zrozumienia funkcji. Użycie () wyraźnie wskazuje, że nie ma potrzeby skanowania kodu w celu ewentualnego użycia _ (co naruszyłoby konwencję). Ale otworzyłeś mi oczy, aby rozważyć również wartość udokumentowania, że ​​funkcja jest przekazywana wartość, która w przeciwnym razie nie zawsze byłaby oczywista.
Zatrzymaj
Właśnie zdałem sobie sprawę, że mój kod jest pełen nieużywanych _zmiennych funkcji strzałek s, zastanawiam się, czy jest jakaś różnica w wydajności w porównaniu z używaniem()
Mojimi,
25

Myślę, że _ =>jest po prostu używany, () =>ponieważ _jest powszechny w innych językach, w których nie można po prostu pomijać parametrów, jak w JS.

_ jest popularny w Go i jest również używany w Dart, aby wskazać, że parametr jest ignorowany i prawdopodobnie inne, o których nie wiem.

Günter Zöchbauer
źródło
4
Myślę, że Python również przestrzega tej konwencji.
Jaime RGP
7
To użycie _prawdopodobnie zostało zapożyczone z języków funkcjonalnych, takich jak ML i Haskell, gdzie jest na długo przed wynalezieniem Pythona (nie mówiąc już o Go, Dart czy TypeScript).
ruakh
1
robi to również Ruby ( poru.com/diary/rubys-magic-underscore ) i F # też (i inne języki, na które wpływ ma rodzina ML)
Mariusz Pawelski
Scala uwielbia podkreślenia ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). Jakie więcej języków zajęło po tym, co robi Scala z anonimowymi typami z podkreśleniem.
Sam
Chyba Scala wzięła to również z innego języka. W językach programowania nie ma prawie niczego, co nie istniało jeszcze w latach 70-tych: D Przeważnie są to tylko nowe sposoby łączenia rzeczy.
Günter Zöchbauer
11

Możliwe jest rozróżnienie między tymi dwoma zastosowaniami, a niektóre frameworki używają tego do reprezentowania różnych typów wywołań zwrotnych. Na przykład myślę, że nodes Express Framework używa tego do rozróżnienia typów oprogramowania pośredniego, na przykład programy obsługi błędów używają trzech argumentów, podczas gdy routing używa dwóch.

Takie zróżnicowanie może wyglądać jak na poniższym przykładzie:

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
źródło
1
Opiera się to na odpowiedzi Bergi, ale pomyślałem, że dodanie przykładu było trochę bardziej edytowalne, niż z radością robiąc posty kogoś innego.
Michael Anderson
0

Kiedy pisałem ten post, byłem pod wrażeniem, _że jedyny sposób na stworzenie funkcji strzałkowych bez niego ()doprowadził mnie do przekonania, że ​​używanie _może mieć drobne zalety, ale się myliłem. @Halt potwierdził w komentarzach, że zachowuje się tak jak inne zmienne, nie jest to specjalna konstrukcja językowa.


Chcę wspomnieć o jeszcze jednej rzeczy, którą zdałem sobie sprawę z tych funkcji podkreślenia strzałek podczas testowania siebie, o których nigdzie nie wspomniałem. Państwo może używać podkreślenia w funkcji jako parametr , choć prawdopodobnie nie ma zastosowania, ponieważ to ma reprezentować nieużywany parametr. Dla jasności nie polecałbym używania go w ten sposób. ale może się przydać wiedza o takich rzeczach jak codegolf , wyzwania, w których piszesz najkrótszy kod (okazuje się, że możesz po prostu użyć dowolnego znaku bez ()). Mogę sobie wyobrazić prawdziwe przypadki użycia, w których biblioteki używają tego i trzeba go używać, nawet jeśli nie zamierzały korzystać z tej funkcji.

Przykład:

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

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

Testowane z konsolą Chrome, wersja 76.0.3809.132 (oficjalna kompilacja) (64-bitowa)

Matsyir
źródło
1
Podkreślenie „_” jest poprawną nazwą zmiennej, a nie specjalną konstrukcją językową, która zgodnie z konwencją ma tylko specjalne znaczenie. Ostrzeżenia dotyczące linterów dotyczące nieużywanych parametrów można wyciszyć za pomocą przedrostka podkreślenia. Myślę, że _ samo w sobie jest najkrótszym sposobem na określenie nieużywanego.
Zatrzymaj
@Halt Dzięki za wyjaśnienie, dobrze wiedzieć na pewno. Właściwie nie zdawałem sobie sprawy, że możesz tworzyć funkcje strzałkowe bez tego, ()zanim napisałem ten post, pomyślałem, że _to jedyny sposób, dlatego postanowiłem to wskazać. Mając to na uwadze, okazuje się, że nie jest to nic specjalnego, nawet do gry w golfa, ponieważ można po prostu użyć zwykłej postaci. Lepiej używać po prostu do przestrzegania konwencji, jak powiedziałeś.
Matsyir,