Dlaczego mogę użyć funkcji przed jej zdefiniowaniem w JavaScript?

Ten kod zawsze działa, nawet w różnych przeglądarkach:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

Nie mogłem znaleźć ani jednego odniesienia do tego, dlaczego to powinno działać. Po raz pierwszy zobaczyłem to w notatce prezentacyjnej Johna Resiga, ale tylko o tym wspomniano. Nie ma żadnego wytłumaczenia.

Czy ktoś mógłby mnie oświecić?
Author: Peter Mortensen, 2008-11-04

7 answers

Deklaracja function jest magiczna i powoduje, że jej identyfikator jest związany, zanim cokolwiek w jej bloku kodu * zostanie wykonane.

To różni się od przypisania wyrażeniem function, które jest oceniane w normalnej kolejności odgórnie.

Jeśli zmieniłeś przykład na:

var internalFoo = function() { return true; };
Przestałoby działać.

Deklaracja funkcji jest składniowo zupełnie oddzielona od wyrażenia funkcji, mimo że wyglądają prawie identycznie i mogą być niejednoznaczne w niektórych sprawy.

Jest to udokumentowane w standard ECMAScript , sekcja 10.1.3. Niestety ECMA-262 nie jest zbyt czytelnym dokumentem nawet jak na standardy-standardy!

*: zawiera funkcję, blok, moduł lub skrypt.

 224
Author: bobince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 12:28:01

Nazywa się to podnoszeniem - wywołaniem (wywołaniem) funkcji przed jej zdefiniowaniem.

Dwa różne typy funkcji, o których chcę napisać to:

Funkcje Wyrażeń I Funkcje Deklaracji

  1. Funkcje Wyrażenia:

    Wyrażenia funkcji mogą być przechowywane w zmiennej, więc nie potrzebują nazw funkcji. Będą one również nazwane jako funkcja anonimowa (funkcja bez nazwy).

    Aby wywołać (wywołać) te funkcje zawsze need a nazwa zmiennej. Tego rodzaju funkcja nie będzie działać, jeśli zostanie wywołana przed zdefiniowaniem, co oznacza, że podnoszenie nie dzieje się tutaj. Zawsze musimy najpierw zdefiniować funkcję wyrażenia, a następnie ją wywołać.

    let lastName = function (family) {
     console.log("My last name is " + family);
    };
    let x = lastName("Lopez");
    

    Tak można to zapisać w ECMAScript 6:

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
    
  2. Funkcje Deklaracji:

    Funkcje zadeklarowane w następującej składni nie są wykonywane natychmiast. Są "zapisywane do późniejszego użycia" i zostaną wykonane później, gdy są wywoływane(wywoływane). Ten typ funkcji działa, jeśli wywołasz ją przed lub po zdefiniowaniu where is. Wywołanie funkcji deklaracji przed jej zdefiniowaniem działa poprawnie.

    function Name(name) {
      console.log("My cat's name is " + name);
    }
    Name("Chloe");
    

    Przykład podnoszenia:

    Name("Chloe");
    function Name(name) {
       console.log("My cat's name is " + name);
    }
    
 35
Author: Negin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-13 16:51:22

Przeglądarka odczytuje Twój HTML Od początku do końca i może go wykonać, ponieważ jest odczytywany i przetwarzany na kawałki wykonywalne (deklaracje zmiennych, definicje funkcji itp.), Ale w dowolnym momencie może używać tylko tego, co zostało zdefiniowane w skrypcie przed tym punktem.

Różni się to od innych kontekstów programistycznych, które przetwarzają (kompilują) cały kod źródłowy, być może łączą go z dowolnymi bibliotekami potrzebnymi do rozwiązywania odniesień i konstruują moduł wykonywalny, w którym to momencie rozpoczyna się egzekucja.

Twój kod może odnosić się do nazwanych obiektów (zmiennych, innych funkcji, itp.), które są zdefiniowane dalej, ale nie można wykonać kodu odwołującego, dopóki wszystkie elementy nie będą dostępne.

Jak już zaznajomisz się z JavaScript, staniesz się świadomy konieczności pisania rzeczy w odpowiedniej kolejności.

Revision: aby potwierdzić zaakceptowaną odpowiedź (powyżej), użyj Firebug, aby przejść przez sekcję skryptu strony internetowej. Zobaczysz, że zostanie pominięty z funkcji aby funkcjonować, odwiedzając tylko pierwszą linię, zanim faktycznie wykona jakikolwiek kod.

 14
Author: dkretz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-29 00:48:54

Niektóre języki mają wymóg, że identyfikatory muszą być zdefiniowane przed użyciem. Powodem tego jest to, że kompilator używa pojedynczego przejścia w kodzie źródłowym.

Ale jeśli jest wiele przejść (lub niektóre kontrole są odroczone) można doskonale żyć bez tego wymogu. W tym przypadku kod jest prawdopodobnie najpierw odczytywany (i interpretowany), a następnie ustawiane są odnośniki.

 4
Author: Toon Krijthe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 11:47:21

Używałem tylko trochę JavaScript. Nie jestem pewien, czy to pomoże, ale wygląda bardzo podobnie do tego, o czym mówisz i może dać pewien wgląd: {]}

Http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

 2
Author: RailsSon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-08 18:15:51

Ciało funkcji "internalFoo" musi iść gdzieś w czasie parsowania, więc kiedy kod jest odczytywany (aka parsowanie) przez interpreter JS, struktura danych dla funkcji jest tworzona i przypisywana nazwa.

Dopiero później, wtedy kod jest uruchomiony, JavaScript rzeczywiście próbuje dowiedzieć się, czy "internalFoo" istnieje i co to jest i czy można go wywołać, itd.

 1
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 11:52:31

Z tego samego powodu w globalnej przestrzeni nazw zawsze umieszcza się foo:

if (test condition) {
    var foo;
}
 -4
Author: Andrew Hedges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 17:38:23