Właściwe użycie stałej do definiowania funkcji w JavaScript

183

Interesuje mnie, czy istnieją ograniczenia co do tego, jakie typy wartości można ustawić za pomocą constJavaScript - w poszczególnych funkcjach. Czy to jest ważne? To prawda, że ​​działa, ale czy z jakiegoś powodu jest uważane za złą praktykę?

const doSomething = () => {
   ...
}

Czy wszystkie funkcje powinny być zdefiniowane w ten sposób w ES6? Wydaje się, że tak się nie stało.

Dziękuję za wszelkie komentarze!

David Sinclair
źródło
Wydaje się, że zadajesz wiele pytań: 1) „Jestem zainteresowany, czy istnieją jakieś ograniczenia co do tego, jakie typy wartości można ustawić za pomocą const w JavaScript” Nie. 2) „Czy to jest poprawne?” Tak. 3) „czy to jest uważane za złą praktykę z jakiegokolwiek powodu”. Wydaje mi się, że nie było wystarczająco długo, aby cokolwiek powiedzieć na ten temat, ale nie rozumiem, dlaczego to powinna być praktyka pad. To niewiele różni się od var doSomething = <function def>;. 4) „Czy wszystkie funkcje powinny być zdefiniowane w ten sposób w ES6?” Wydaje mi się kłopotliwy. Lubię deklaracje funkcji. Każdy ma swoje.
Felix Kling,
1
Z mojego punktu widzenia (opinia, a nie fakt) ma sens, jeśli chcesz zabronić redefiniowania funkcji. Niezależnie od tego, czy jest to rozsądne, czy ma jakieś zastosowanie funkcjonalne - to dyskusyjne. Jeśli uważasz, że pasuje to do twojego scenariusza użytkowania, nie sądzę, aby ktoś mógł podważyć twoją decyzję i uznać ją za złą praktykę.
Mjh,
4
Myślę, że pytanie brzmi: co chcesz osiągnąć const. Czy chcesz uchronić się przed zastąpieniem funkcji? Zakładam, że znasz swój kod, aby tego nie robić. Czy chcesz wyrazić zamiar doSomething, tzn. Że pełni on funkcję i nie zmienia swojej wartości? Wydaje mi się, że deklaracje funkcji również jasno wyrażają ten zamiar. Jeśli więc potrzebujesz „ochrony środowiska wykonawczego” przed zastąpieniem, skorzystaj z niej. W przeciwnym razie nie widzę większych korzyści. Oczywiście, jeśli głównie używałeś var foo = function() {};, użyłbym constzamiast var.
Felix Kling,
5
@ FelixKling: „Zakładam, że znasz swój kod, aby i tak tego nie robić”. - to dość zły argument. W przeciwnym razie nie ma to żadnego sensu const.
meandre

Odpowiedzi:

253

Nie ma problemu z tym, co zrobiłeś, ale musisz pamiętać różnicę między deklaracjami funkcji i wyrażeniami funkcji.

Deklaracja funkcji, to znaczy:

function doSomething () {}

Jest w całości podnoszony na szczyt zakresu (i tym podobne, leti constmają również zakres blokowy).

Oznacza to, że następujące funkcje będą działać:

doSomething() // works!
function doSomething() {}

Wyrażenie funkcyjne, to znaczy:

[const | let | var] = function () {} (or () =>

Jest utworzeniem anonimowej funkcji ( function () {}) i utworzeniem zmiennej, a następnie przypisaniem tej anonimowej funkcji do tej zmiennej.

Zatem zwykłe reguły dotyczące podnoszenia zmiennych w zakresie - zmienne o zasięgu blokowym ( leti const) nie podnoszą co undefineddo początku zakresu bloków.

To znaczy:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

Błąd, ponieważ doSomethingnie jest zdefiniowany. (Rzuci a ReferenceError)

Jeśli przełączysz się na używanie var, otrzymasz podnoszenie zmiennej, ale zostanie ona zainicjowana, aby undefinedpowyższy blok kodu nadal nie działał. (Wyrzuci to, TypeErrorże doSomethingnie jest funkcją w momencie jej wywołania)

Jeśli chodzi o standardowe praktyki, zawsze powinieneś używać odpowiedniego narzędzia do pracy.

Axel Rauschmayer ma świetny post na temat zakresu i podnoszenia, w tym semantyki es6: Zmienne i określanie zakresu w ES6

tkone
źródło
7
Chciałbym tylko dodać, że klasy es6 używają const wewnętrznie do ochrony nazwy klasy przed ponownym przypisaniem w klasie.
user2342460,
2
Jedna subtelna różnica między a function a(){console.log(this);} i b const a=_=>{console.log(this);} polega na tym, że nazwijmy to tak a.call(someVar);, jak w a , wydrukuje someVar, w b , wydrukuje window.
Qian Chen
100

Chociaż używanie constdo definiowania funkcji wydaje się być włamaniem, ale ma kilka wspaniałych zalet, które czynią go lepszym (moim zdaniem)

  1. Sprawia, że ​​funkcja jest niezmienna, więc nie musisz się martwić, że funkcja ta zostanie zmieniona przez inny fragment kodu.

  2. Możesz użyć składni Fat Arrow, która jest krótsza i czystsza.

  3. Używanie funkcji strzałek dba o thiswiązanie dla Ciebie.

przykład z function

// define a function
function add(x, y) { return x + y; }

// use it
console.log(add(1, 2)); // 3

// oops, someone mutated your function
add = function (x, y) { return x - y; };

// now this is not what you expected
console.log(add(1, 2)); // -1

ten sam przykład z const

// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;

// use it
console.log(add(1, 2)); // 3

// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged

gafi
źródło
1
I możesz dwukrotnie zadeklarować funkcję add (x, y), ale nie możesz zadeklarować dwa razy const add = ...
TatianaP
33
1. Niezmienność jest prawdziwą korzyścią, ale bardzo rzadko ktoś zastępuje funkcję. 2. Składnia grubej strzałki nie jest krótsza, chyba że twoja funkcja może być wyrażeniem. function f(x, y) {ma 18 znaków, const f = (x, y) => {ma 21 znaków, więc 3 znaki dłuższe. 3. Zachowanie tego wiązania ma znaczenie tylko wtedy, gdy funkcje są zdefiniowane w metodzie (lub innej funkcji, która ma to znaczenie). Na najwyższym poziomie skrypt jest bezcelowy. Nie twierdzę, że się mylisz, tylko dlatego, że wymienione przez ciebie przyczyny nie są zbyt istotne.
Nakedible
@Nakedible, więc jakie są inne ważne powody?
Anish Ramaswamy
13
Jedną z zalet starej składni funkcji jest to, że podczas debugowania ma swoją nazwę.
user949300
3
Użyłbym włókien, aby zapobiec ponownemu wiązaniu deklaracji funkcji.
Franklin Yu
32

Minęły trzy lata, odkąd zadano to pytanie, ale dopiero teraz się z nim spotykam. Ponieważ ta odpowiedź jest tak daleko w dół, pozwól mi ją powtórzyć:

P: Interesuje mnie, czy istnieją ograniczenia co do tego, jakie typy wartości można ustawić za pomocą const w JavaScript - w poszczególnych funkcjach. Czy to jest ważne? To prawda, że ​​działa, ale czy z jakiegoś powodu jest uważane za złą praktykę?

Byłem zmotywowany do przeprowadzenia pewnych badań po zaobserwowaniu jednego płodnego kodera JavaScript, który zawsze używa constinstrukcji functions, nawet jeśli nie ma wyraźnego powodu / korzyści.

W odpowiedzi na pytanie „ czy to jest uważane za złą praktykę z jakiegokolwiek powodu? ”, Pozwól mi powiedzieć, IMO, tak, to jest, a przynajmniej istnieją zalety korzystania ze functionstwierdzenia.

Wydaje mi się, że jest to w dużej mierze kwestia preferencji i stylu. Istnieje kilka dobrych argumentów przedstawionych powyżej, ale żaden nie jest tak jasny, jak w tym artykule:

Ciągłe zamieszanie: dlaczego wciąż używam instrukcji funkcji JavaScript medium.freecodecamp.org/Bill Sourour, guru JavaScript, konsultant i nauczyciel.

Wzywam wszystkich do przeczytania tego artykułu, nawet jeśli już podjęliście decyzję.

Oto główne punkty:

Instrukcje funkcyjne mają dwie wyraźne zalety w stosunku do wyrażeń funkcyjnych [const]:

Zaleta nr 1: Jasność zamiarów

Skanując tysiące wierszy kodu dziennie, warto być w stanie zrozumieć intencje programisty tak szybko i łatwo, jak to możliwe.

Korzyść nr 2: Kolejność deklaracji == kolejność wykonania

Idealnie chciałbym zadeklarować mój kod mniej więcej w takiej kolejności, w jakiej oczekuję, że zostanie on wykonany.

To jest dla mnie showstopper: każda wartość zadeklarowana za pomocą słowa kluczowego const jest niedostępna, dopóki nie osiągnie go wykonanie.

To, co właśnie opisałem powyżej, zmusza nas do pisania kodu, który wygląda do góry nogami. Musimy zacząć od funkcji najniższego poziomu i iść dalej.

Mój mózg nie działa w ten sposób. Chcę kontekst przed szczegółami.

Większość kodu jest pisana przez ludzi. Ma więc sens, że porządek zrozumienia większości ludzi z grubsza odpowiada porządkowi wykonania większości kodów.

JMichaelTX
źródło
1
Czy możesz komentować nieco więcej na temat jasności intencji? Dostaję # 2, ale o ile wiem, że # 1 to tylko (pre?) Powtórzenie # 2. Mogę wymyślić przypadek, tj. Funkcje, które mają defaultErrorHandlerprzypisane własne const jako funkcję anonimową, którą mogę następnie wywołać z programów obsługi obietnic. Umożliwiłoby mi to opcjonalne „zastąpienie” tej domyślnej procedury obsługi błędów w funkcjach, tak jak potrzebowałem. Niektórzy po prostu zwracają obiekt błędu, a inni zwracają odpowiedź HTTP o różnym poziomie szczegółowości. Jednak struktura kodu może być znanym wzorcem niezależnie.
Jake T.,
Może mój pomysł jest jednak zbyt skomplikowany! Otaczając głowę nowymi praktykami, nie spędziłem jeszcze dużo czasu na ich wdrażaniu. Po prostu stwierdziłem, że naprawdę lubię .then( res.success, res.error )znacznie więcej niż anonimowe funkcje, które zamierzałem po prostu wywołać res.success(value);. Posiadanie .then( ..., defaultErrorHandler)wspólnego wzorca może być przyjemne, ze zdefiniowaną na najwyższym poziomie funkcją defaultErrorHandler i opcjonalnie mieć const defaultErrorHandler = error => { ... }zadeklarowany zakres funkcji zgodnie z potrzebami.
Jake T.,
1
@JakeT. RE „Czy możesz komentować nieco więcej na temat jasności intencji?”. Cóż, po pierwsze, oświadczenie to nie zostało wydane przeze mnie, ale przez freecodecamp.org/Bill Sourour, autora tego artykułu. Ale to ma dla mnie prawdziwy zdrowy rozsądek. Jeśli przeczytam „funkcja jutro ()”, od razu wiem, że JEST to funkcja. Ale jeśli przeczytam „const tomorrow = () =>”, zatrzymam się na chwilę i przeanalizuję składnię w głowie, aby w końcu ustalić, OK, tak, to jest funkcja.
JMichaelTX,
1
Inna sprawa, jeśli mam długi skrypt napisany przez kogoś innego i chcę zobaczyć wszystkie funkcje, mogę szybko wyszukać „funkcję”, aby je znaleźć. Lub jeszcze lepiej, mogę napisać szybki JS RegEx, aby wyodrębnić wszystkie funkcje. IMO, instrukcja „const” dotyczy tylko danych (a nie funkcji), które NIE ulegną zmianie.
JMichaelTX,
10

Istnieje kilka bardzo ważnych korzyści z używania, consta niektórzy twierdzą, że należy go używać wszędzie tam, gdzie to możliwe, ze względu na to, jak celowe i indykatywne jest.

Jest to, o ile mogę powiedzieć, najbardziej indykatywna i przewidywalna deklaracja zmiennych w JavaScript oraz jedna z najbardziej przydatnych PONIEWAŻ, jak bardzo jest ograniczona. Czemu? Ponieważ eliminuje niektóre dostępne możliwości vari letdeklaracje.

Co możesz wywnioskować, czytając const? Znasz wszystkie poniższe elementy, czytając constdeklarację ORAZ bez skanowania innych odniesień do tej zmiennej:

  • wartość jest powiązana z tą zmienną (chociaż jej podstawowy obiekt nie jest głęboko niezmienny)
  • nie można uzyskać do niego dostępu poza jego bezpośrednio zawierającym blokiem
  • wiązanie nigdy nie jest dostępne przed zgłoszeniem, z powodu przepisów dotyczących strefy czasowej martwej (TDZ).

Poniższy cytat pochodzi z artykułu uzasadniającego zalety leti const. Bardziej bezpośrednio odpowiada na pytanie dotyczące ograniczeń / ograniczeń słowa kluczowego:

Ograniczenia, takie jak te oferowane przez leti constsą potężnym sposobem na ułatwienie zrozumienia kodu. Spróbuj zapisać jak najwięcej z tych ograniczeń w pisanym kodzie. Im bardziej deklaratywne ograniczenia, które ograniczają znaczenie fragmentu kodu, tym łatwiej i szybciej ludzie mogą czytać, analizować i rozumieć fragment kodu w przyszłości.

To prawda, że constdeklaracja zawiera więcej reguł niż vardeklaracja: zakres blokowy, TDZ, przypisz w deklaracji, bez zmiany przypisania. Natomiast varinstrukcje sygnalizują jedynie zasięg funkcji. Jednak liczenie reguł nie daje wiele wglądu. Lepiej jest rozważyć te reguły pod względem złożoności: czy reguła dodaje lub odejmuje złożoność? W przypadku constzakresu blokowego oznacza zakres węższy niż zakres funkcji, TDZ oznacza, że ​​nie musimy skanować zakresu wstecz od deklaracji w celu wykrycia użycia przed deklaracją, a reguły przypisania oznaczają, że wiązanie zawsze zachowa to samo odniesienie.

Im bardziej ograniczone są instrukcje, tym prostszy staje się fragment kodu. Gdy dodamy ograniczenia do tego, co może oznaczać instrukcja, kod staje się mniej nieprzewidywalny. Jest to jeden z głównych powodów, dla których programy o typie statycznym są ogólnie łatwiejsze do odczytania niż programy o typie dynamicznym. Pisanie statyczne nakłada duże ograniczenia na twórcę programu, ale nakłada również duże ograniczenia na sposób interpretacji programu, dzięki czemu jego kod jest łatwiejszy do zrozumienia.

Mając na uwadze te argumenty, zaleca się, aby używać consttam, gdzie to możliwe, ponieważ jest to stwierdzenie, które daje nam najmniej możliwości do przemyślenia.

Źródło: https://ponyfoo.com/articles/var-let-const

mrmaclean89
źródło