Kolejność funkcji JavaScript: dlaczego ma to znaczenie?

Pytanie Pierwotne:

JSHint narzeka, gdy mój JavaScript wywołuje funkcję, która jest zdefiniowana dalej na stronie niż jej wywołanie. Jednak moja strona jest dla gry i żadne funkcje nie są wywoływane, dopóki całość nie zostanie pobrana. Dlaczego więc funkcje kolejności pojawiają się w moim kodzie mają znaczenie?

EDIT: chyba znalazłem odpowiedź.

Http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

Jęczę w środku. Wygląda na to, że muszę spędzić kolejny dzień, zamawiając sześć tysięcy linijek kodu. Krzywa uczenia się z javascript nie jest stroma, ale jest bardzo looooong.
Author: Incognito, 2011-09-30

4 answers

Tl; dr Jeśli nic nie dzwonisz, dopóki wszystko się nie załaduje, powinno być dobrze.


Edit: dla przeglądu, który obejmuje również niektóre deklaracje ES6(let, const): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

To dziwne zachowanie zależy od

  1. jak definiujesz funkcje i
  2. Kiedy do nich zadzwonisz.

Oto kilka przykłady.

bar(); //This won't throw an error
function bar() {}

foo(); //This will throw an error
var foo = function() {}

----

bar();
function bar() {
    foo(); //This will throw an error
}
var foo = function() {}

----

bar();
function bar() {
    foo(); //This _won't_ throw an error
}
function foo() {}

---

function bar() {
    foo(); //no error
}
var foo = function() {}
bar();

To z powodu czegoś, co nazywa się podnoszeniem!

Istnieją dwa sposoby definiowania funkcji: Function declaration oraz function expression . Różnica jest irytująca i minuta, więc powiedzmy to trochę źle: jeśli piszesz to jak function name() {}, to jest to deklaracja , a kiedy piszesz to jak var name = function() {} (lub anonimowa funkcja przypisana do zwrotu, takie rzeczy), to jest to funkcja wyrażenie.

Najpierw przyjrzyjmy się, jak zmienne są obsługiwane:

var foo = 42;

//the interpreter turns it into this:
var foo;
foo = 42;

Teraz, jak funkcja deklaracje są obsługiwane:

var foo = 42;
function bar() {}

//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;

The var statements "rzuca" utworzenie z foo na sam szczyt, ale nie przypisuje mu jeszcze wartości. Deklaracja funkcji jest następująca w linii, a na koniec przypisana jest wartość foo.

A co z tym?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;

Zostaje przeniesiona tylko deklaracja z foo na szczyt. Przypisanie następuje dopiero po wywołaniu bar, gdzie było przed wystąpieniem wszystkich podnośników.

I wreszcie, dla zwięzłości:

bar();
function bar() {}
//turns to
function bar() {}
bar();

A co z funkcjami wyrażeniami ?

var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();

Podobnie jak zwykłe zmienne, najpierw foo jest zadeklarowane w najwyższym punkcie zakresu, a następnie jest przypisana wartość.

Zobaczmy, dlaczego drugi przykład rzuca błąd.

bar();
function bar() {
    foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
    foo();
}
bar();
foo = function() {}

Jak widzieliśmy wcześniej, tylko tworzenie foo jest podnoszone, przypisanie przychodzi tam, gdzie pojawiło się w kodzie" oryginalnym " (un-hoisted). Gdy wywołane jest bar, to przed foo zostanie przypisana wartość, więc foo === undefined. Teraz w ciele funkcji bar, to tak, jakbyś robił undefined(), co powoduje błąd.

 256
Author: Zirak,
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-03-08 17:37:59

Głównym powodem jest prawdopodobnie to, że JSLint przekazuje tylko jeden plik, więc nie wie, że zdefiniuje taką funkcję.

Jeśli użyto składni instrukcji functions

function foo(){ ... }

Nie ma żadnej różnicy, gdzie deklarujesz funkcję (zawsze zachowuje się tak, jakby deklaracja była na początku).

Z drugiej strony, jeśli twoja funkcja była ustawiona jak zwykła zmienna

var foo = function() { ... };

Musisz zagwarantować, że nie zadzwonisz przed inicjalizacja (może to być rzeczywiście źródłem błędów).


Ponieważ zmiana kolejności kodu jest skomplikowana i sama w sobie może być źródłem błędów, sugerowałbym szukanie obejścia problemu. Jestem prawie pewien, że możesz wcześniej podać JSLint nazwę globalnych zmiennych, aby nie narzekał na nierejestrowane rzeczy.

Dodaj komentarz do początku pliku

/*globals foo1 foo2 foo3*/

Lub możesz użyć do tego pola tekstowego. (Myślę też, że można to przekazać w argumentach do wewnętrzna funkcja jslint, jeśli możesz się z nią mieszać.)

 6
Author: hugomg,
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
2015-01-23 14:15:08

Jest zbyt wiele osób forsujących dowolne zasady dotyczące pisania JavaScript. Większość zasad to bzdury.

Funkcja podnoszenia jest funkcją w JavaScript, ponieważ jest to dobry pomysł.

Jeśli masz wewnętrzną funkcję, która jest często użytecznością funkcji wewnętrznych, dodanie jej do początku zewnętrznej funkcji jest akceptowalnym stylem pisania kodu, ale ma tę wadę, że musisz przeczytać szczegóły, aby dostać się do tego, co zewnętrzne Funkcja Tak.

Powinieneś trzymać się jednej zasady w swojej bazie kodowej albo umieść funkcje prywatne jako pierwsze, albo jako ostatnie w module lub funkcji. JSHint jest dobry do egzekwowania spójności, ale należy bezwzględnie dostosować .jshintrc dopasować do Twoich potrzeb, a nie dostosować swój kod źródłowy do innych ludzi zwariowanych koncepcji kodowania.

Jeden styl kodowania, który możesz zobaczyć na wolności, którego powinieneś unikać, ponieważ nie daje on żadnych korzyści, a jedynie możliwą refaktoryzację ból:

function bigProcess() {
    var step1,step2;
    step1();
    step2();

    step1 = function() {...};
    step2 = function() {...};
}

To jest dokładnie to, czego funkcja podnoszenia jest tam, aby uniknąć. Po prostu naucz się języka i wykorzystaj jego mocne strony.

 3
Author: Henrik Vendelbo,
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
2015-04-19 10:00:44

Tylko deklaracja funkcji jest podnoszona, a nie wyrażenie funkcji (przypisanie).

 1
Author: Abhay Srivastav,
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-13 05:46:38