Zgodnie z propozycją , strzały miały na celu „rozwiązanie i rozwiązanie kilku typowych problemów związanych z tradycyjnym Function Expression
”. Zamierzali poprawić sprawy, wiążąc this
leksykalnie i oferując zwięzłą składnię.
Jednak,
- Nie można konsekwentnie wiązać
this
leksykalnie
- Składnia funkcji strzałek jest delikatna i niejednoznaczna
Dlatego funkcje strzałek stwarzają możliwość pomyłek i błędów i należy je wyłączyć ze słownika programisty JavaScript, zastępując je function
wyłącznie.
Odnośnie leksykalnej this
this
jest problematyczne:
function Book(settings) {
this.settings = settings;
this.pages = this.createPages();
}
Book.prototype.render = function () {
this.pages.forEach(function (page) {
page.draw(this.settings);
}, this);
};
Funkcje strzałek mają rozwiązać problem polegający na tym, że musimy uzyskać dostęp do właściwości this
wewnątrz wywołania zwrotnego. Jest już na to kilka sposobów: Można przypisać this
do zmiennej, użyć bind
lub użyć trzeciego argumentu dostępnego w Array
metodach agregujących. Jednak strzałki wydają się być najprostszym obejściem, więc metodę można by zmienić w następujący sposób:
this.pages.forEach(page => page.draw(this.settings));
Zastanów się jednak, czy kod używał biblioteki takiej jak jQuery, której metody wiążą się this
specjalnie. Teraz this
mamy do czynienia z dwiema wartościami:
Book.prototype.render = function () {
var book = this;
this.$pages.each(function (index) {
var $page = $(this);
book.draw(book.currentPage + index, $page);
});
};
Musimy używać function
, each
aby wiązać się this
dynamicznie. Nie możemy tutaj użyć funkcji strzałki.
Radzenie sobie z wieloma this
wartościami może być również mylące, ponieważ trudno jest ustalić, o którym this
autor mówił:
function Reader() {
this.book.on('change', function () {
this.reformat();
});
}
Czy autor rzeczywiście chciał zadzwonić Book.prototype.reformat
? A może zapomniał związać this
i zamierzał zadzwonić Reader.prototype.reformat
? Jeśli zmienimy moduł obsługi na funkcję strzałki, podobnie będziemy się zastanawiać, czy autor chciał dynamiki this
, ale wybrał strzałkę, ponieważ pasuje do jednej linii:
function Reader() {
this.book.on('change', () => this.reformat());
}
Można postawić: „Czy to wyjątkowe, że strzałki mogą być czasem niewłaściwą funkcją? Być może, jeśli rzadko potrzebujemy this
wartości dynamicznych , to nadal byłoby dobrze używać strzałek przez większość czasu”.
Ale zadaj sobie następujące pytanie: „Czy warto byłoby debugować kod i stwierdzić, że wynikiem błędu był„ przypadek na krawędzi ”?” Wolałbym unikać problemów nie tylko przez większość czasu, ale także 100% czasu.
Jest lepszy sposób: Zawsze używaj function
(więc this
zawsze może być dynamicznie związany) i zawsze odwołuj się this
przez zmienną. Zmienne są leksykalne i przyjmują wiele nazw. Przypisanie this
do zmiennej wyjaśni twoje intencje:
function Reader() {
var reader = this;
reader.book.on('change', function () {
var book = this;
book.reformat();
reader.reformat();
});
}
Co więcej, zawsze przypisywanie this
do zmiennej (nawet gdy istnieje jedna this
lub żadna inna funkcja) zapewnia, że intencje pozostają jasne nawet po zmianie kodu.
Ponadto dynamika this
nie jest niczym wyjątkowym. jQuery jest używany na ponad 50 milionach stron internetowych (od tego pisania w lutym 2016 r.). Oto inne interfejsy API wiążące się this
dynamicznie:
- Mocha (wczoraj ~ 120 tys. Pobrań) udostępnia metody testów za pośrednictwem
this
.
- Grunt (wczoraj ~ 63 tys. Pobrań) udostępnia metody tworzenia zadań za pośrednictwem
this
.
- Backbone (wczoraj ~ 22 000 pobrań) określa metody dostępu
this
.
- API Imprez (jak Doma) odnoszą się do ugrupowania
EventTarget
z this
.
- Prototypowe interfejsy API, które są załatane lub rozszerzone, odnoszą się do instancji z
this
.
(Statystyki za pośrednictwem http://trends.builtwith.com/javascript/jQuery i https://www.npmjs.com .)
Prawdopodobnie już potrzebujesz this
powiązań dynamicznych .
this
Czasem oczekuje się leksyki , ale czasem nie; tak jak this
czasami oczekuje się dynamiki , ale czasem nie. Na szczęście istnieje lepszy sposób, który zawsze wytwarza i komunikuje oczekiwane wiązanie.
Odnośnie skróconej składni
Funkcje strzałek zapewniły „krótszą formę składniową” dla funkcji. Ale czy te krótsze funkcje sprawią, że odniesiesz większy sukces?
Czy x => x * x
„łatwiej jest czytać” niż function (x) { return x * x; }
? Być może jest tak, ponieważ bardziej prawdopodobne jest wygenerowanie jednego, krótkiego wiersza kodu. Według Dysona Wpływ prędkości odczytu i długości linii na skuteczność odczytu z ekranu ,
Wydaje się, że średnia długość linii (55 znaków na linię) wspiera efektywny odczyt przy normalnej i dużej prędkości. Spowodowało to najwyższy poziom zrozumienia. . .
Podobne uzasadnienia dotyczą operatora warunkowego (trójskładnikowego) i if
instrukcji jednowierszowych .
Czy naprawdę piszesz proste funkcje matematyczne reklamowane we wniosku ? Moje domeny nie są matematyczne, więc moje podprogramy rzadko są tak eleganckie. Często widzę, że funkcje strzałek przekraczają limit kolumn i zawijają się do innej linii ze względu na edytor lub przewodnik po stylu, który niweluje „czytelność” według definicji Dysona.
Można by postawić: „A może po prostu użyć krótkiej wersji do krótkich funkcji, jeśli to możliwe?” Ale teraz reguła stylistyczna stoi w sprzeczności z ograniczeniami językowymi: „Spróbuj użyć możliwie najkrótszej notacji funkcji, pamiętając, że czasami tylko najdłuższa notacja wiąże się this
zgodnie z oczekiwaniami”. Takie pomieszanie sprawia, że strzały są szczególnie podatne na niewłaściwe użycie.
Istnieje wiele problemów ze składnią funkcji strzałek:
const a = x =>
doSomething(x);
const b = x =>
doSomething(x);
doSomethingElse(x);
Obie te funkcje są poprawne pod względem składniowym. Ale doSomethingElse(x);
nie ma go w treści b
, jest to po prostu słabo wcięte oświadczenie najwyższego poziomu.
Po rozwinięciu do postaci bloku nie ma już domniemania return
, którego przywrócenie można zapomnieć. Ale to wyrażenie mogło mieć jedynie na celu wywołanie efektu ubocznego, więc kto wie, czy wyraźne return
będzie konieczne w przyszłości?
const create = () => User.create();
const create = () => {
let user;
User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
const create = () => {
let user;
return User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
To, co może być przeznaczone jako parametr spoczynkowy, można przeanalizować jako operator rozkładania:
processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest
Przypisanie można pomylić z domyślnymi argumentami:
const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parens
Bloki wyglądają jak obiekty:
(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object
Co to znaczy?
() => {}
Czy autor miał zamiar utworzyć brak operacji lub funkcję zwracającą pusty obiekt? (Mając to na uwadze, powinniśmy zawsze umieszczać {
po =>
? Powinniśmy ograniczyć się tylko do składni wyrażeń? To by jeszcze bardziej zmniejszyć częstotliwość strzałkami.)
=>
wygląda <=
i >=
:
x => 1 ? 2 : 3
x <= 1 ? 2 : 3
if (x => 1) {}
if (x >= 1) {}
Aby natychmiast wywołać wyrażenie funkcji strzałki, należy umieścić je ()
na zewnątrz, ale umieszczenie ()
w środku jest prawidłowe i może być zamierzone.
(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function
Chociaż, jeśli ktoś pisze (() => doSomething()());
z zamiarem napisania natychmiast wywołanego wyrażenia funkcyjnego, po prostu nic się nie wydarzy.
Trudno argumentować, że funkcje strzałek są „bardziej zrozumiałe”, biorąc pod uwagę wszystkie powyższe przypadki. Jeden mógł poznać wszystkie szczególne zasady niezbędne do wykorzystania tej składni. Czy to naprawdę jest tego warte?
Składnia function
jest wyjątkowo uogólniona. Używanie function
wyłącznie oznacza, że sam język zapobiega pisaniu mylącego kodu. Aby napisać procedury, które powinny być rozumiane syntaktycznie we wszystkich przypadkach, wybieram function
.
Jeśli chodzi o wytyczne
Prosisz o wytyczne, które muszą być „jasne” i „spójne”. Użycie funkcji strzałek ostatecznie spowoduje powstanie poprawnego pod względem składniowym, logicznie niepoprawnego kodu, z obiema formami funkcji splecionymi, sensownie i arbitralnie. Dlatego oferuję:
Wytyczne dotyczące notacji funkcji w ES6:
- Zawsze twórz procedury za pomocą
function
.
- Zawsze przypisuj
this
do zmiennej. Nie używać () => {}
.
Fixed this bound to scope at initialisation
ograniczenie?