Niedawno zacząłem utrzymywać kod JavaScript innej osoby. Naprawiam błędy, dodaje funkcje, a także próbuję uporządkować kod i uczynić go bardziej spójnym.
Poprzedni programista zastosował dwa sposoby deklarowania funkcji i nie mogę się zorientować, czy jest to uzasadnione czy nie.
Dwa sposoby to:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Jakie są powody korzystania z tych dwóch różnych metod i jakie są zalety i wady każdej z nich? Czy jest coś, co można zrobić za pomocą jednej metody, czego nie można zrobić za pomocą drugiej?
javascript
function
syntax
idioms
Richard Garside
źródło
źródło
var a = 1; var b = 2;
staje sięvar a; var b; a = 1; b = 2
. Kiedy deklarujesz functionOne, zostaje zadeklarowane, ale jego wartość nie jest ustawiana natychmiast. Ponieważ functionTwo to tylko deklaracja, zostaje umieszczona na szczycie zakresu. # 2 functionTwo pozwala uzyskać dostęp do właściwości name, co bardzo pomaga w próbach debugowania.function f(){}
Vs.var f = function(){};
Odpowiedzi:
Różnica polega na tym, że
functionOne
jest wyrażeniem funkcyjnym, a więc jest definiowana tylko po osiągnięciu tego wiersza, podczas gdyfunctionTwo
jest deklaracją funkcji i jest definiowana natychmiast po wykonaniu otaczającej funkcji lub skryptu (z powodu podnoszenia ).Na przykład wyrażenie funkcyjne:
I deklaracja funkcji:
Historycznie deklaracje funkcji zdefiniowane w blokach były obsługiwane niespójnie między przeglądarkami. Tryb ścisły (wprowadzony w ES5) rozwiązał ten problem, scopując deklaracje funkcji do ich otaczającego bloku.
źródło
functionOne
jest jedynie zmienną, do której przypisano anonimową funkcję, podczas gdy wfunctionTwo
rzeczywistości jest funkcją nazwaną. Zadzwoń.toString()
do obu, aby zobaczyć różnicę. Jest to istotne w niektórych przypadkach, gdy chcesz programowo uzyskać nazwę funkcji.function expression
drugi, a drugi tofunction declaration
. Możesz przeczytać więcej na ten temat tutaj: javascriptweblog.wordpress.com/2010/07/06/…Najpierw chcę poprawić Grega:
function abc(){}
ma równieżabc
zasięg - nazwa jest zdefiniowana w zakresie, w którym napotyka się tę definicję. Przykład:Po drugie, możliwe jest połączenie obu stylów:
xyz
zostanie zdefiniowany jak zwykle, nieabc
jest zdefiniowany we wszystkich przeglądarkach, ale Internet Explorer - nie polegaj na tym, że jest definiowany. Ale zostanie zdefiniowane w jego ciele:Jeśli chcesz aliasować funkcje we wszystkich przeglądarkach, użyj tego rodzaju deklaracji:
W tym przypadku oba są
xyz
iabc
są aliasami tego samego obiektu:Jednym z istotnych powodów, dla których warto zastosować połączony styl, jest atrybut „name” obiektów funkcyjnych ( nie obsługiwany przez Internet Explorer ). Zasadniczo po zdefiniowaniu funkcji takiej jak
jego nazwa jest przypisywana automatycznie. Ale kiedy to zdefiniujesz
jego nazwa jest pusta - stworzyliśmy anonimową funkcję i przypisaliśmy ją do jakiejś zmiennej.
Innym dobrym powodem do użycia połączonego stylu jest użycie krótkiej nazwy wewnętrznej w celu odniesienia się do siebie, przy jednoczesnym zapewnieniu użytkownikom zewnętrznym długiej, nie powodującej konfliktu nazwy:
W powyższym przykładzie możemy zrobić to samo z zewnętrzną nazwą, ale będzie ona zbyt nieporęczna (i wolniejsza).
(Innym sposobem na odwołanie się do siebie jest użycie
arguments.callee
, które wciąż jest stosunkowo długie i nie jest obsługiwane w trybie ścisłym).W głębi duszy JavaScript traktuje obie instrukcje inaczej. To jest deklaracja funkcji:
abc
tutaj jest zdefiniowane wszędzie w bieżącym zakresie:Ponadto wyciągnął
return
oświadczenie:To jest wyrażenie funkcyjne:
xyz
tutaj jest zdefiniowane od miejsca przypisania:Deklaracja funkcji a wyrażenie funkcji jest prawdziwym powodem, dla którego istnieje różnica wykazana przez Grega.
Śmieszny fakt:
Osobiście wolę deklarację „wyrażenie funkcji”, ponieważ w ten sposób mogę kontrolować widoczność. Kiedy zdefiniuję funkcję jak
Wiem, że zdefiniowałem tę funkcję lokalnie. Kiedy zdefiniuję funkcję jak
Wiem, że zdefiniowałem to globalnie, pod warunkiem, że nie zdefiniowałem
abc
nigdzie w łańcuchu zakresów. Ten styl definicji jest elastyczny, nawet gdy jest używany w środkueval()
. Podczas definicjizależy od kontekstu i może sprawić, że zgadniesz, gdzie jest on faktycznie zdefiniowany, szczególnie w przypadku
eval()
- odpowiedź brzmi: to zależy od przeglądarki.źródło
var abc = function(){}; console.log(abc.name);
nie produkuje""
więcej, ale"abc"
zamiast tego.Oto podsumowanie standardowych formularzy tworzących funkcje: (Pierwotnie napisane dla innego pytania, ale dostosowane po przeniesieniu do pytania kanonicznego).
Warunki:
Szybka lista:
Deklaracja funkcji
function
Wyrażenie „anonimowe” (które pomimo tego terminu czasami tworzy funkcje o nazwach)O nazwie
function
wyrażenieInicjator funkcji akcesoriów (ES5 +)
Wyrażenie funkcji strzałki (ES2015 +) (które, podobnie jak anonimowe wyrażenia funkcji, nie wymaga wyraźnej nazwy, a jednak może tworzyć funkcje o nazwach)
Deklaracja metody w inicjalizatorze obiektów (ES2015 +)
Deklaracja konstruktora i metody w
class
(ES2015 +)Deklaracja funkcji
Pierwsza forma to deklaracja funkcji , która wygląda następująco:
Deklaracja funkcji jest deklaracją ; to nie jest stwierdzenie ani wyrażenie. W związku z tym nie podążasz za nim
;
(chociaż jest to nieszkodliwe).Deklaracja funkcji jest przetwarzana, gdy wykonanie wejdzie w kontekst, w którym się pojawia, przed wykonaniem dowolnego kodu krok po kroku. Funkcja, którą tworzy, otrzymuje odpowiednią nazwę (
x
w powyższym przykładzie), a nazwa ta jest umieszczana w zakresie, w którym pojawia się deklaracja.Ponieważ jest przetwarzany przed dowolnym kodem krok po kroku w tym samym kontekście, możesz wykonywać następujące czynności:
Aż ES2015, spec nie obejmowały co silnik JavaScript należy zrobić, jeśli umieścić deklarację funkcji wewnątrz struktury kontrolnej jak
try
,if
,switch
,while
, itd., Jak poniżej:A ponieważ są one przetwarzane przed uruchomieniem kodu krok po kroku, trudno jest wiedzieć, co robić, gdy są w strukturze kontroli.
Chociaż nie zostało to określone do ES2015, było to dopuszczalne rozszerzenie do obsługi deklaracji funkcji w blokach. Niestety (i nieuchronnie) różne silniki robiły różne rzeczy.
Od wersji ES2015 specyfikacja mówi, co robić. W rzeczywistości daje trzy różne rzeczy do zrobienia:
Reguły dla trybów swobodnych są trudne, ale w trybie ścisłym deklaracje funkcji w blokach są łatwe: są lokalne dla bloku (mają zakres bloku , który jest również nowy w ES2015) i są podnoszone na szczyt bloku. Więc:
function
Wyrażenie „anonimowe”Druga popularna forma nazywa się anonimowym wyrażeniem funkcji :
Podobnie jak wszystkie wyrażenia, jest on oceniany, gdy zostanie osiągnięty podczas wykonywania kodu krok po kroku.
W ES5 utworzona funkcja nie ma nazwy (jest anonimowa). W ES2015 funkcja ma przypisaną nazwę, jeśli to możliwe, na podstawie kontekstu. W powyższym przykładzie nazwą byłoby
y
. Coś podobnego robi się, gdy funkcja jest wartością inicjatora właściwości. (Aby uzyskać szczegółowe informacje o tym, kiedy to się dzieje i zasady, wyszukajSetFunctionName
w specyfikacji - pojawia się wszędzie ).Nazwane
function
wyrażenieTrzecia postać to nazwane wyrażenie funkcyjne („NFE”):
Ta funkcja ma prawidłową nazwę (
w
w tym przypadku). Podobnie jak wszystkie wyrażenia, jest to oceniane, gdy jest osiągane w krokowym wykonaniu kodu. Nazwa funkcji nie jest dodawana do zakresu, w którym pojawia się wyrażenie; nazywa się w zakresie samej funkcji:Zauważ, że NFE często były źródłem błędów w implementacjach JavaScript. Na przykład IE8 i wcześniejsze obsługują NFE całkowicie niepoprawnie , tworząc dwie różne funkcje w dwóch różnych momentach. Wczesne wersje Safari również miały problemy. Dobrą wiadomością jest to, że obecne wersje przeglądarek (IE9 i nowsze, obecne Safari) nie mają już tych problemów. (Ale od tego pisania, niestety, IE8 jest nadal w powszechnym użyciu, więc używanie NFE z kodem dla Internetu jest ogólnie problematyczne.)
Inicjator funkcji akcesoriów (ES5 +)
Czasami funkcje mogą się wkraść w dużej mierze niezauważone; tak jest w przypadku funkcji akcesoriów . Oto przykład:
Pamiętaj, że kiedy korzystałem z tej funkcji, nie korzystałem
()
! To dlatego, że to funkcja akcesorium dla właściwości. Otrzymujemy i ustawiamy właściwość w normalny sposób, ale za kulisami funkcja jest wywoływana.Można również tworzyć dostępowe z funkcji
Object.defineProperty
,Object.defineProperties
oraz mniej znanych drugiego argumentuObject.create
.Wyrażenie funkcji strzałki (ES2015 +)
ES2015 oferuje nam funkcję strzałki . Oto jeden przykład:
Zobacz, jak ta
n => n * 2
rzecz ukrywa się wmap()
rozmowie? To jest funkcja.Kilka rzeczy na temat funkcji strzałek:
Nie mają swoich
this
. Zamiast tego blisko nadthis
od kontekstu, w którym są one zdefiniowane. (Zamykają się równieżarguments
i, w stosownych przypadkachsuper
). Oznacza to, żethis
ich wnętrze jest takie samo, jak miejsce, wthis
którym zostały utworzone i nie można ich zmienić.Jak zauważyłeś powyżej, nie używasz słowa kluczowego
function
; zamiast tego używasz=>
.Powyższy
n => n * 2
przykład jest jedną z nich. Jeśli masz wiele argumentów do przekazania funkcji, użyj parens:(Zapamietaj to
Array#map
przekazuje wpis jako pierwszy argument, a indeks jako drugi).W obu przypadkach treść funkcji jest tylko wyrażeniem; wartość zwracana przez funkcję będzie automatycznie wynikiem tego wyrażenia (nie używasz wyrażenia jawnego)
return
).Jeśli robisz więcej niż tylko jedno wyrażenie, użyj
{}
i jawnegoreturn
(jeśli musisz zwrócić wartość), jak zwykle:Wersja bez
{ ... }
jest nazywana funkcją strzałki z treścią wyrażenia lub zwięzłą treścią . (Również: zwięzła funkcja strzałki.) Ta z{ ... }
definiowaniem ciała jest funkcją strzałki z ciałem funkcji . (Również: pełna funkcja strzałki).Deklaracja metody w inicjalizatorze obiektów (ES2015 +)
ES2015 pozwala na krótszą formę deklarowania właściwości odwołującej się do funkcji zwanej definicją metody ; To wygląda tak:
prawie odpowiednikiem w ES5 i wcześniejszych byłoby:
różnica (inna niż gadatliwość) polega na tym, że metoda może użyć
super
, ale funkcja nie. Na przykład, jeśli miałbyś obiekt, który zdefiniował (powiedzmy)valueOf
za pomocą składni metody, mógłby go użyć,super.valueOf()
aby uzyskać wartość,Object.prototype.valueOf
którą zwróciłoby (zanim prawdopodobnie zrobiłby z nią coś innego), podczas gdy wersja ES5 musiałaby to zrobićObject.prototype.valueOf.call(this)
.Oznacza to również, że metoda ma odwołanie do obiektu, na którym została zdefiniowana, więc jeśli ten obiekt jest tymczasowy (na przykład przekazujesz go
Object.assign
jako jeden z obiektów źródłowych), składnia metody może oznaczać, że obiekt jest zachowany w pamięci, gdy w przeciwnym razie można by go wyrzucić (jeśli silnik JavaScript nie wykryje tej sytuacji i obsłuży ją, jeśli żadna z metod nie zastosujesuper
).Deklaracja konstruktora i metody w
class
(ES2015 +)ES2015 zapewnia nam
class
składnię, w tym deklarowane konstruktory i metody:Powyżej znajdują się dwie deklaracje funkcji: jedna dla konstruktora, który otrzymuje nazwę
Person
, i jedna dlagetFullName
, która jest funkcją przypisanąPerson.prototype
.źródło
w
jest po prostu ignorowana?Mówiąc o kontekście globalnym, zarówno
var
instrukcja, jak iFunctionDeclaration
na końcu utworzą nieusuwalną właściwość na obiekcie globalnym, ale wartość obu można zastąpić .Subtelna różnica między tymi dwoma sposobami polega na tym, że gdy uruchomiony zostanie proces tworzenia zmiennej (przed faktycznym wykonaniem kodu), wszystkie identyfikatory zadeklarowane za pomocą
var
zostaną zainicjowaneundefined
, a identyfikatory używane przez teFunctionDeclaration
będą dostępne od tego momentu, na przykład:Przypisywanie zdarzeń
bar
FunctionExpression
odbywa się do czasu wykonania.Globalna właściwość utworzona przez a
FunctionDeclaration
może być nadpisana bez żadnych problemów, podobnie jak wartość zmiennej, np .:Inną oczywistą różnicą między twoimi dwoma przykładami jest to, że pierwsza funkcja nie ma nazwy, ale druga ma ją, co może być bardzo przydatne podczas debugowania (tj. Sprawdzania stosu wywołań).
Jeśli chodzi o edytowany pierwszy przykład (
foo = function() { alert('hello!'); };
), jest to niezadeklarowane zadanie, gorąco zachęcam do korzystania zevar
słowa kluczowego.Przy przypisaniu, bez
var
instrukcji, jeśli odnośny identyfikator nie zostanie znaleziony w łańcuchu zasięgu, stanie się usuwalną właściwością obiektu globalnego.Ponadto niezadeklarowane zadania wrzucają
ReferenceError
ECMAScript 5 w trybie ścisłym .Musisz to przeczytać:
Uwaga : Ta odpowiedź została połączona z innym pytaniem , w którym główną wątpliwością i błędnym przekonaniem PO było to, że identyfikatory zadeklarowane za pomocą
FunctionDeclaration
, nie mogą zostać zastąpione, co nie jest prawdą.źródło
Dwa fragmenty kodu, które tam opublikowałeś, będą działały tak samo, dla prawie wszystkich celów.
Różnica w zachowaniu polega jednak na tym, że w pierwszym wariancie (
var functionOne = function() {}
) tę funkcję można wywołać dopiero po tym punkcie kodu.W drugim wariancie (
function functionTwo()
) funkcja jest dostępna dla kodu działającego powyżej miejsca, w którym funkcja jest zadeklarowana.Jest tak, ponieważ w pierwszym wariancie funkcja jest przypisana do zmiennej
foo
w czasie wykonywania. W drugim przypadku funkcja jest przypisana do tego identyfikatorafoo
w czasie analizy.Więcej informacji technicznych
JavaScript ma trzy sposoby definiowania funkcji.
eval()
przypadku problemów.źródło
Lepsze wyjaśnienie odpowiedzi Grega
Dlaczego nie ma błędu? Zawsze uczono nas, że wyrażenia są wykonywane od góry do dołu (??)
Ponieważ:
Oznacza to, że taki kod:
Zauważ, że część przypisania deklaracji nie została podniesiona. Podnoszona jest tylko nazwa.
Ale w przypadku deklaracji funkcji podniesiony zostanie również cały obiekt funkcji :
źródło
Inni komentatorzy opisali już różnicę semantyczną dwóch powyższych wariantów. Chciałem zauważyć różnicę stylistyczną: tylko odmiana „przypisania” może ustawić właściwość innego obiektu.
Często buduję moduły JavaScript z takim wzorcem:
Dzięki temu wzorcowi wszystkie funkcje publiczne będą używać przypisania, a funkcje prywatne - deklaracji.
(Należy również pamiętać, że przypisanie powinno wymagać średnika po instrukcji, podczas gdy deklaracja tego zabrania).
źródło
var foo = function(){...}
składni nawet w przypadku zmiennych prywatnych.function window.onload() {}
było coś.)Ilustracją tego, kiedy preferować pierwszą metodę od drugiej, jest to, kiedy należy unikać zastępowania poprzednich definicji funkcji.
Z
, ta definicja
myfunction
zastąpi każdą poprzednią definicję, ponieważ zostanie wykonana w czasie analizy.Podczas
wykonuje prawidłowe zadanie definiowania
myfunction
tylko wtedy, gdycondition
jest spełniony.źródło
var myFunc = null;
poza pętlą lub poza blokiem if / elseif / else. Następnie możesz warunkowo przypisać różne funkcje do tej samej zmiennej. W JS lepszym rozwiązaniem jest przypisanie brakującej wartości wartości null, a następnie niezdefiniowanej. Dlatego najpierw powinieneś zadeklarować myFunction jako null, a następnie przypisać go później, warunkowo.Ważnym powodem jest dodanie jednej i tylko jednej zmiennej jako „root” przestrzeni nazw ...
lub
Istnieje wiele technik dotyczących przestrzeni nazw. Staje się to coraz ważniejsze dzięki mnogości dostępnych modułów JavaScript.
Zobacz także Jak zadeklarować przestrzeń nazw w JavaScript?
źródło
Podnoszenie to działanie interpretera JavaScript polegające na przeniesieniu wszystkich deklaracji zmiennych i funkcji na szczyt bieżącego zakresu.
Jednak podnoszone są tylko rzeczywiste deklaracje. pozostawiając zadania tam, gdzie są.
Zmienna
JavaScript jest nazywany językiem luźno pisanym. Co oznacza, że zmienne JavaScript mogą przechowywać wartość dowolnego typu danych . Javascript automatycznie dba o zmianę typu zmiennej na podstawie wartości / literału podanych podczas działania.
Funkcjonować
Domyślna wartość zwracana przez funkcję to „ niezdefiniowana ”, domyślna wartość deklaracji zmiennej również „niezdefiniowana”
Deklaracja funkcji
Wyrażenie funkcji
Funkcja przypisana do zmiennej Przykład:
javascript interpretowany jako
Możesz sprawdzić deklarację funkcji, test ekspresji przy użyciu różnych przeglądarek
jsperf Test Runner
Klasy funkcji konstruktora ES5 : Obiekty funkcji utworzone za pomocą Function.prototype.bind
JavaScript traktuje funkcje jak obiekty pierwszej klasy, więc będąc obiektem, możesz przypisywać właściwości do funkcji.
ES6 wprowadził funkcję strzałki: Wyrażenie funkcji strzałki ma krótszą składnię, najlepiej nadają się do funkcji niemetodowych i nie można ich używać jako konstruktorów.
źródło
Dodam własną odpowiedź tylko dlatego, że wszyscy dokładnie zakryli część podnoszącą.
Od dłuższego czasu zastanawiałem się, która droga jest lepsza, a dzięki http://jsperf.com teraz wiem :)
Deklaracje funkcji są szybsze, a to naprawdę ma znaczenie w web dev, prawda? ;)
źródło
Deklaracja funkcji i wyrażenie funkcji przypisane do zmiennej zachowują się tak samo po ustanowieniu powiązania.
Istnieje jednak różnica w tym, jak i kiedy obiekt funkcji jest faktycznie powiązany z jego zmienną. Różnica wynika z mechanizmu zwanego podnoszeniem zmiennych w JavaScript.
Zasadniczo wszystkie deklaracje funkcji i deklaracje zmiennych są przenoszone na szczyt funkcji, w której występuje deklaracja (dlatego mówimy, że JavaScript ma zakres funkcji ).
Kiedy deklaracja funkcji jest podnoszona, ciało funkcji „podąża”, więc gdy ciało funkcji jest oceniane, zmienna zostanie natychmiast powiązana z obiektem funkcji.
Gdy podnoszona jest deklaracja zmiennej, inicjalizacja nie następuje, ale zostaje „pozostawiona”. Zmienna jest inicjalizowana
undefined
na początku treści funkcji i zostanie przypisana wartość w pierwotnym miejscu w kodzie. (W rzeczywistości zostanie mu przypisana wartość w każdym miejscu, w którym występuje deklaracja zmiennej o tej samej nazwie).Ważna jest również kolejność podnoszenia: deklaracje funkcji mają pierwszeństwo przed deklaracjami zmiennych o tej samej nazwie, a ostatnia deklaracja funkcji ma pierwszeństwo przed poprzednimi deklaracjami funkcji o tej samej nazwie.
Kilka przykładów...
Zmienna
foo
jest podnoszony do góry funkcji, zainicjowanymundefined
, tak że!foo
jesttrue
, tofoo
jest przypisany10
.foo
Pozabar
„s zakresie odgrywa żadnej roli i jest nietknięte.Deklaracje funkcji mają pierwszeństwo przed deklaracjami zmiennych, a ostatnia deklaracja funkcji „trzyma się”.
W tym przykładzie
a
jest inicjowany obiektem funkcji wynikającym z oceny drugiej deklaracji funkcji, a następnie jest przypisywany4
.Tutaj deklaracja funkcji jest najpierw podnoszona, deklarując i inicjując zmienną
a
. Następnie ta zmienna jest przypisywana10
. Innymi słowy: przypisanie nie przypisuje zmiennej zewnętrzneja
.źródło
Pierwszym przykładem jest deklaracja funkcji:
Drugi przykład to wyrażenie funkcyjne:
Główną różnicą jest sposób ich podnoszenia (podnoszenia i deklarowania). W pierwszym przykładzie podnoszona jest cała deklaracja funkcji. W drugim przykładzie podnoszony jest tylko var 'abc', jego wartość (funkcja) będzie niezdefiniowana, a sama funkcja pozostanie w pozycji, w której została zadeklarowana.
Krótko mówiąc:
Aby dowiedzieć się więcej na ten temat, zdecydowanie polecam ten link
źródło
Pod względem kosztów utrzymania kodu, nazwane funkcje są bardziej preferowane:
Podejrzewam, że następują kolejne PROS dla nazwanych funkcji. Zaletą nazwanych funkcji jest wada anonimowych.
Historycznie, anonimowe funkcje powstały z niemożności JavaScript jako języka do listy członków o nazwanych funkcjach:
źródło
W kategoriach informatyki mówimy o funkcjach anonimowych i nazwanych. Myślę, że najważniejszą różnicą jest to, że funkcja anonimowa nie jest związana z nazwą, stąd nazwa funkcji anonimowej. W JavaScript jest to obiekt pierwszej klasy dynamicznie zadeklarowany w czasie wykonywania.
Aby uzyskać więcej informacji na temat funkcji anonimowych i rachunku lambda, Wikipedia jest dobrym początkiem ( http://en.wikipedia.org/wiki/Anonymous_function ).
źródło
Używam podejścia zmiennego w moim kodzie z bardzo konkretnego powodu, którego teoria została omówiona powyżej w sposób abstrakcyjny, ale przykład może pomóc niektórym osobom takim jak ja, z ograniczoną znajomością JavaScript.
Mam kod, który muszę uruchomić z 160 niezależnie zaprojektowanymi brandami. Większość kodu znajduje się we współdzielonych plikach, ale elementy specyficzne dla marki znajdują się w osobnym pliku, po jednym dla każdej marki.
Niektóre marki wymagają określonych funkcji, a niektóre nie. Czasami muszę dodawać nowe funkcje, aby wykonywać nowe czynności związane z brandingiem. Cieszę się, że mogę zmienić wspólne kodowanie, ale nie chcę zmieniać wszystkich 160 zestawów plików brandingowych.
Korzystając ze składni zmiennej, mogę zadeklarować zmienną (zasadniczo wskaźnik funkcji) we wspólnym kodzie i albo przypisać trywialną funkcję pośredniczącą, albo ustawić wartość null.
Jeden lub dwa brandingi, które wymagają konkretnej implementacji funkcji, mogą następnie zdefiniować swoją wersję funkcji i przypisać ją do zmiennej, jeśli chcą, a reszta nic nie robi. Mogę przetestować funkcję zerową przed wykonaniem jej we wspólnym kodzie.
Z powyższych komentarzy ludzi wynika, że może być również możliwe przedefiniowanie funkcji statycznej, ale myślę, że zmienne rozwiązanie jest ładne i jasne.
źródło
Odpowiedź Grega jest wystarczająco dobra, ale nadal chciałbym dodać do niej coś, czego nauczyłem się właśnie oglądając filmy Douglasa Crockforda .
Wyrażenie funkcji:
Instrukcja funkcji:
Instrukcja funkcji jest tylko skrótem dla
var
instrukcji ofunction
wartości.Więc
rozwija się do
Który rozszerza się dalej do:
I oba są podnoszone na szczyt kodu.
źródło
Istnieją cztery godne uwagi porównania między dwiema różnymi deklaracjami funkcji wymienionymi poniżej.
Następujące działa, ponieważ
function add()
jest ograniczone do najbliższego bloku:Poniższe nie działa, ponieważ zmienna jest wywoływana przed przypisaniem wartości funkcji do zmiennej
add
.Powyższy kod ma identyczną funkcjonalność jak poniższy kod. Zauważ, że jawne przypisywanie
add = undefined
jest zbędne, ponieważ samo robienievar add;
jest dokładnie takie samo jakvar add=undefined
.Poniższe nie działa, ponieważ
var add=
zastępujefunction add()
.Nazwa funkcji
function thefuncname(){}
to nazwafunkcji, gdy jest deklarowana w ten sposób.W przeciwnym razie, jeśli funkcja zostanie zadeklarowana jako
function(){}
, funkcja .nazwa jest pierwszą zmienną używaną do przechowywania funkcji.Jeśli nie ma żadnych zmiennych ustawionych dla funkcji, nazwa funkcji jest pustym ciągiem (
""
).Wreszcie, podczas gdy zmienna, do której funkcja jest przypisana, początkowo ustawia nazwę, kolejne zmienne ustawione dla funkcji nie zmieniają nazwy.
W Google V8 i Spidermonkey w Firefoksie może występować kilka mikrosekundowych różnic w kompilacji JIST, ale ostatecznie wynik jest dokładnie taki sam. Aby to udowodnić, przyjrzyjmy się wydajności JSPerf przy znakach mikrodruku, porównując szybkość dwóch pustych fragmentów kodu. Te testy JSPerf są tutaj znaleźć . I testy jsben.ch znajdują się tutaj . Jak widać, zauważalna jest różnica, kiedy nie powinno jej być. Jeśli naprawdę jesteś maniakiem wydajności, takim jak ja, może być bardziej warte wysiłku, starając się zmniejszyć liczbę zmiennych i funkcji w zakresie, a zwłaszcza eliminując polimorfizm (np. Używając tej samej zmiennej do przechowywania dwóch różnych typów).
Kiedy używasz
var
słowa kluczowego do deklarowania zmiennej, możesz następnie przypisać inną wartość do zmiennej w ten sposób.Kiedy jednak użyjemy instrukcji const, odwołanie do zmiennej staje się niezmienne. Oznacza to, że nie możemy przypisać nowej wartości do zmiennej. Należy jednak pamiętać, że nie powoduje to, że zawartość zmiennej jest niezmienna: jeśli tak
const arr = []
, to nadal możnaarr[10] = "example"
. Tylko zrobienie czegoś podobnegoarr = "new value"
lubarr = []
spowodowałoby błąd, jak pokazano poniżej.Co ciekawe, jeśli zadeklarujemy zmienną jako
function funcName(){}
, wówczas niezmienność zmiennej jest taka sama, jak jej zadeklarowanievar
.Co to jest „najbliższy blok”
„Najbliższy blok” to najbliższa „funkcja” (w tym funkcje asynchroniczne, funkcje generatora i funkcje asynchronicznego generatora). Jednak, co ciekawe,
function functionName() {}
zachowuje się jak wvar functionName = function() {}
przypadku bloku, który nie jest zamknięty dla przedmiotów poza wspomnianym zamknięciem. Przestrzegać.var add=function(){}
function add(){}
if
,else
,for
,while
,try
/catch
/finally
,switch
,do
/while
,with
)var add=function()
function add()
źródło
@EugeneLazutkin podaje przykład, w którym nazywa przypisaną funkcję, aby móc jej używać
shortcut()
jako wewnętrznego odwołania do siebie. John Resig podaje inny przykład - kopiowanie funkcji rekurencyjnej przypisanej do innego obiektu w swoim samouczku Learning Advanced JavaScript . Chociaż przypisywanie funkcji do właściwości nie jest tu dokładnie pytaniem, polecam aktywnie wypróbować samouczek - uruchom kod, klikając przycisk w prawym górnym rogu, i dwukrotnie kliknij kod, aby edytować według własnych upodobań.Przykłady z samouczka: wywołania rekurencyjne w
yell()
:Testy kończą się niepowodzeniem po usunięciu oryginalnego obiektu ninja. (strona 13)
Jeśli nazwiesz funkcję, która będzie wywoływana rekurencyjnie, testy zakończą się pomyślnie. (strona 14)
źródło
Inną różnicą, która nie została wymieniona w innych odpowiedziach, jest to, że jeśli używasz funkcji anonimowej
i użyj tego jako konstruktora jak w
wtedy
one.constructor.name
nie zostanie zdefiniowany.Function.name
jest niestandardowy, ale jest obsługiwany przez Firefox, Chrome, inne przeglądarki pochodzące z Webkit i IE 9+.Z
możliwe jest pobranie nazwy konstruktora jako ciągu za pomocą
two.constructor.name
.źródło
Pierwszy (funkcja doSomething (x)) powinien być częścią notacji obiektowej.
Drugi (
var doSomething = function(x){ alert(x);}
) polega po prostu na utworzeniu anonimowej funkcji i przypisaniu jej do zmiennej,doSomething
. Zatem doSomething () wywoła tę funkcję.Możesz chcieć wiedzieć, czym jest deklaracja funkcji i wyrażenie funkcji .
Deklaracja funkcji definiuje nazwaną zmienną funkcyjną bez konieczności przypisywania zmiennej. Deklaracje funkcji występują jako samodzielne konstrukcje i nie można ich zagnieżdżać w blokach niefunkcjonalnych.
W powyższym stanie nazwa funkcji jest widoczna w jej zakresie i zakresie jej rodzica (w przeciwnym razie byłby nieosiągalny).
I w wyrażeniu funkcyjnym
Wyrażenie funkcyjne definiuje funkcję jako część większej składni wyrażenia (zazwyczaj przypisanie zmiennej). Funkcje zdefiniowane za pomocą wyrażeń funkcji mogą być nazwane lub anonimowe. Wyrażenia funkcyjne nie powinny zaczynać się od „funkcja”.
źródło
Poniżej wymieniam różnice:
Deklarację funkcji można umieścić w dowolnym miejscu kodu. Nawet jeśli zostanie wywołana, zanim definicja pojawi się w kodzie, zostanie wykonana, gdy deklaracja funkcji zostanie zapisana w pamięci lub w taki sposób, że zostanie podniesiona, zanim jakikolwiek inny kod na stronie rozpocznie wykonywanie.
Spójrz na poniższą funkcję:
Wynika to z faktu, że podczas wykonywania wygląda to tak:
Wyrażenie funkcyjne, jeśli nie zostanie zdefiniowane przed wywołaniem, spowoduje błąd. Również tutaj sama definicja funkcji nie jest przenoszona na górę ani zapisywana w pamięci, jak w deklaracjach funkcji. Ale zmienna, do której przypisujemy funkcję, zostaje podniesiona i niezdefiniowana zostaje do niej przypisana.
Ta sama funkcja przy użyciu wyrażeń funkcyjnych:
Wynika to z faktu, że podczas wykonywania wygląda to tak:
Zapisywanie deklaracji funkcji w blokach niefunkcyjnych nie jest bezpieczne, na przykład jeśli nie będą one dostępne.
Nazwane wyrażenie funkcyjne, takie jak poniższe, może nie działać w przeglądarkach Internet Explorer wcześniejszych niż wersja 9.
źródło
Jeśli użyjesz tych funkcji do tworzenia obiektów, otrzymasz:
źródło
console.log(objectOne.__proto__);
wypisuje „functionOne {}” na mojej konsoli. Wszelkie pomysły, dlaczego tak może być?W świetle argumentu „nazwane funkcje pojawiają się w śladach stosu”, nowoczesne silniki JavaScript są w rzeczywistości całkiem zdolne do reprezentowania funkcji anonimowych.
W tym piśmie V8, SpiderMonkey, Chakra i Nitro zawsze odnoszą się do nazwanych funkcji po ich nazwach. Niemal zawsze odnoszą się do funkcji anonimowej według jej identyfikatora, jeśli ona ma taką funkcję.
SpiderMonkey może ustalić nazwę anonimowej funkcji zwróconej z innej funkcji. Reszta nie może.
Jeśli naprawdę bardzo chciałeś, aby iterator i zwrotne informacje o sukcesie pojawiały się w śladzie, możesz też wymienić te ...
Ale w przeważającej części nie warto się stresować.
Uprząż ( skrzypce )
V8
Pająk Małpa
Czakra
Nitro
źródło
W JavaScript są dwa sposoby tworzenia funkcji:
Deklaracja funkcji:
Jest to bardzo proste, zrozumiałe, stosowane w wielu językach i standardowe w całej rodzinie języków C. Zadeklarowaliśmy funkcję, która ją zdefiniowała i wykonała, wywołując ją.
Powinieneś wiedzieć, że funkcje w JavaScript są obiektami; wewnętrznie stworzyliśmy obiekt dla powyższej funkcji i nadaliśmy mu nazwę o nazwie fn lub odwołanie do obiektu jest przechowywane w fn. Funkcje są obiektami w JavaScript; instancja funkcji jest w rzeczywistości instancją obiektu.
Wyrażenie funkcji:
JavaScript ma pierwszorzędne funkcje, to znaczy, stwórz funkcję i przypisz ją do zmiennej, tak jak tworzysz ciąg lub liczbę i przypisz ją do zmiennej. Tutaj zmienna fn jest przypisana do funkcji. Powodem tego pojęcia są funkcje w JavaScript; fn wskazuje na instancję obiektu powyższej funkcji. Zainicjowaliśmy funkcję i przypisaliśmy ją do zmiennej. Nie wykonuje funkcji i nie przypisuje wyniku.
Odwołanie: składnia deklaracji funkcji JavaScript: var fn = function () {} vs function fn () {}
źródło
var fn = function fn() {...}
?Oba są różnymi sposobami definiowania funkcji. Różnica polega na tym, jak przeglądarka interpretuje i ładuje je w kontekście wykonania.
Pierwszy przypadek dotyczy wyrażeń funkcyjnych, które ładują się tylko wtedy, gdy interpreter osiągnie ten wiersz kodu. Więc jeśli zrobisz to w następujący sposób, otrzymasz błąd, że functionOne nie jest funkcją .
Powodem jest to, że w pierwszym wierszu do funkcji Function nie przypisano żadnej wartości, a zatem jest ona niezdefiniowana. Próbujemy to nazwać funkcją, dlatego otrzymujemy błąd.
W drugim wierszu przypisujemy odwołanie funkcji anonimowej do functionOne.
Drugi przypadek dotyczy deklaracji funkcji ładowanych przed wykonaniem jakiegokolwiek kodu. Jeśli więc podoba Ci się poniższy komunikat, nie pojawi się żaden błąd, ponieważ deklaracja ładuje się przed wykonaniem kodu.
źródło
O wydajności:
Nowe wersje
V8
wprowadziły kilka optymalizacji pod maską i tak też się stałoSpiderMonkey
.Obecnie nie ma prawie żadnej różnicy między wyrażeniem a deklaracją.
Wyrażenie funkcji wydaje się teraz szybsze .
Chrome 62.0.3202
FireFox 55
Chrome Canary 63.0.3225
Firefox Chrome Canary Chrome
źródło
Są dość podobne z pewnymi niewielkimi różnicami, pierwsza to zmienna przypisana do funkcji anonimowej (Deklaracja funkcji), a druga to normalny sposób tworzenia funkcji w JavaScript (Deklaracja funkcji anonimowej), zarówno pod względem użycia, wad, jak i zalet :
1. Wyrażenie funkcji
Przypisanie zmiennej do funkcji oznacza brak podnoszenia, ponieważ wiemy, że funkcje w JavaScript mogą podnosić, oznacza, że można je wywoływać zanim zostaną zadeklarowane, podczas gdy zmienne muszą zostać zadeklarowane przed uzyskaniem dostępu do nich, więc w tym przypadku nie możemy uzyskać dostęp do funkcji przed jej zadeklarowaniem, może to być również sposób pisania funkcji, dla funkcji, które zwracają inną funkcję, ten rodzaj deklaracji może mieć sens, również w ECMA6 i wyżej można przypisać to do funkcji strzałki, która może być używany do wywoływania funkcji anonimowych, również ten sposób deklarowania jest lepszym sposobem tworzenia funkcji konstruktora w JavaScript.
2. Deklaracja funkcji
Jest to normalny sposób wywoływania funkcji w JavaScript. Funkcję tę można wywołać, zanim jeszcze ją zadeklarujesz, ponieważ w JavaScript wszystkie funkcje są podnoszone, ale jeśli użyjesz opcji „strict”, nie spowoduje to podniesienia zgodnie z oczekiwaniami, jest to dobry sposób wywoływać wszystkie normalne funkcje, które nie są duże w liniach i żadna z nich nie jest funkcją konstruktora.
Ponadto, jeśli potrzebujesz więcej informacji o tym, jak działa podnoszenie w JavaScript, odwiedź poniższy link:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
źródło
...also this way of declaring is a better way to create Constructor functions in JavaScript
, proszę rozwinąć, jestem ciekawy!To tylko dwa możliwe sposoby deklarowania funkcji, a po drugie, możesz użyć funkcji przed deklaracją.
źródło
new Function()
może być użyty do przekazania ciała funkcji w ciągu. I stąd można to wykorzystać do tworzenia funkcji dynamicznych. Również przekazywanie skryptu bez wykonywania skryptu.źródło