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 thisleksykalnie i oferując zwięzłą składnię.
Jednak,
- Nie można konsekwentnie wiązać
thisleksykalnie
- 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 functionwyłą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 thiswewnątrz wywołania zwrotnego. Jest już na to kilka sposobów: Można przypisać thisdo zmiennej, użyć bindlub użyć trzeciego argumentu dostępnego w Arraymetodach 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ę thisspecjalnie. Teraz thismamy 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, eachaby wiązać się thisdynamicznie. Nie możemy tutaj użyć funkcji strzałki.
Radzenie sobie z wieloma thiswartościami może być również mylące, ponieważ trudno jest ustalić, o którym thisautor 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ć thisi 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 thiswartoś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 thiszawsze może być dynamicznie związany) i zawsze odwołuj się thisprzez zmienną. Zmienne są leksykalne i przyjmują wiele nazw. Przypisanie thisdo 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 thisdo zmiennej (nawet gdy istnieje jedna thislub żadna inna funkcja) zapewnia, że intencje pozostają jasne nawet po zmianie kodu.
Ponadto dynamika thisnie 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ę thisdynamicznie:
- 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
EventTargetz 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 thispowiązań dynamicznych .
thisCzasem oczekuje się leksyki , ale czasem nie; tak jak thisczasami 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 ifinstrukcji 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ę thiszgodnie 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 returnbę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 functionjest wyjątkowo uogólniona. Używanie functionwyłą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
thisdo zmiennej. Nie używać () => {}.
Fixed this bound to scope at initialisationograniczenie?