Określanie zakresu i podnoszenie funkcji JavaScript

90

Właśnie przeczytałem świetny artykuł Bena Cherry'a o JavaScript Scoping and Hoisting, w którym podaje następujący przykład:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

Używając powyższego kodu, przeglądarka wyświetli alert „1”.

Nadal nie jestem pewien, dlaczego zwraca „1”. Przychodzą mi na myśl niektóre z rzeczy, które mówi: Wszystkie deklaracje funkcji są podniesione na górę. Zakres zmiennej można określić za pomocą funkcji. Nadal nie klika dla mnie.

deweloper
źródło

Odpowiedzi:

120

Podnoszenie funkcji oznacza, że ​​funkcje są przenoszone na szczyt ich zakresu. To jest,

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

zostanie przepisany przez interpeter do tego

function b() {
  function a() {}
  a = 10;
  return;
}

Dziwne, co?

Również w tym przypadku

function a() {}

zachowywał się tak samo jak

var a = function () {};

Tak więc zasadniczo robi to kod:

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"
Peter Olson
źródło
2
Czyli wszystkie deklaracje funkcji są ostatecznie przypisane do zmiennej?
dev.e.loper
15
@ dev.e.loper Tak, w Javascript funkcje są obiektami pierwszej klasy, podobnie jak łańcuchy i liczby. Oznacza to, że są zdefiniowane jako zmienne i mogą być przekazywane do innych funkcji, przechowywane w tablicach i tak dalej.
Peter Olson
4
W żadnym wypadku treść funkcji nie jest „przepisywana”. Różne standardy ECMAScript jasno określają, że deklaracje zmiennych i funkcji są przetwarzane przed rozpoczęciem wykonywania kodu. Oznacza to, że nic się nie porusza , chodzi o kolejność wykonania (stąd moja niechęć do określenia „podnoszenie”, które sugeruje ruch lub przegrupowanie). W przepisanym kodzie deklaracja var apowinna znajdować się przed deklaracją funkcji, a przypisanie a = 1po. Ale zauważ, że nie jest to określone przez parser, tokeniser, interpreter, kompilator, cokolwiek, to tylko odpowiednik.
RobG
3
@RobG Jasne, myślę, że można by nazwać opis małym „kłamstwem dla dzieci” , ale ostatecznie zachowanie jest takie samo, niezależnie od tego, czy kod jest dosłownie przestawiany, czy tylko kolejność wykonywania jest zmieniana. To, co faktycznie dzieje się za kulisami, jest bardziej akademickie, a nawet może zależeć od implementacji.
Peter Olson,
7
„Również w tym przypadku function a() {}zachowywał się tak samo jak var a = function () {};  - jest to niepoprawne z dwóch powodów: po pierwsze, jeśli w ogóle, to byłoby var a = function a() {};(funkcja nie jest w rzeczywistości anonimowa), po drugie, te dwie formy nie są zamienne, ponieważ var a = function a() {};tylko var a;część zostałaby podniesiona. a = function a() {};Część nadal były za instrukcji return. Ponieważ oryginalna forma jest deklaracją funkcji, a nie wyrażeniem funkcji, w rzeczywistości jest podnoszona jako całość.
user4642212
6

Musisz pamiętać, że analizuje on całą funkcję i rozwiązuje wszystkie deklaracje zmiennych przed jej wykonaniem. Więc....

function a() {} 

naprawdę się staje

var a = function () {}

var a wymusza na nim zakres lokalny, a zakres zmiennej obejmuje całą funkcję, więc zmienna globalna a nadal ma wartość 1, ponieważ zadeklarowałeś a w zakresie lokalnym, czyniąc z niej funkcję.

kemiller2002
źródło
5

Funkcja ajest podnoszona w funkcji b:

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

co jest prawie jak używanie var:

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

Funkcja jest zadeklarowana lokalnie, a ustawienie aodbywa się tylko w zakresie lokalnym, a nie globalnym var.

Cyfrowy samolot
źródło
1
ta linia „var a = function () {};” wyjaśnia wszystko .. w zasadzie JavaScript jest językiem dynamicznym, a „function” jest również obiektem w JavaScript.
refaktoryzacja
3
  1. deklaracja funkcji function a(){}jest podnoszona jako pierwsza i zachowuje się jak var a = function () {};, dlatego w zasięgu lokalnym ajest tworzona.
  2. Jeśli masz dwie zmienne o tej samej nazwie (jedna globalna, druga lokalna), zmienna lokalna ma zawsze pierwszeństwo przed zmienną globalną.
  3. Podczas ustawiania a=10ustawiasz zmienną lokalną a, a nie globalną.

W związku z tym wartość zmiennej globalnej pozostaje taka sama, a otrzymasz powiadomienie 1

Jhankar Mahbub
źródło
1

function a() { }jest instrukcją funkcji, która tworzy azmienną lokalną dla bfunkcji.
Zmienne są tworzone podczas analizowania funkcji, niezależnie od tego, czy instrukcja varlub funkcja zostanie wykonana.

a = 10 ustawia tę zmienną lokalną.

SLaks
źródło
w rzeczywistości a = 10ustawia zmienną w zakresie globalnym, gdy funkcja bjest wykonywana, chyba że dodasz "use strict"(w takich środowiskach, jak obsługa tej dyrektywy).
Sean Vieira,
@Sean: Nie, ponieważ instrukcja funkcji tworzy lokalny identyfikator.
SLaks
... i .... masz rację. Nie zdawałem sobie sprawy z tej szczególnej konsekwencji podnoszenia funkcji. Dzięki!
Sean Vieira,
1

Jaka jest kość niezgody w tym małym fragmencie kodu?

Przypadek 1:

Uwzględnij function a(){}definicję w treści w function bnastępujący sposób.logs value of a = 1

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Przypadek 2

Wyklucz function a(){}definicję wewnątrz treści w function bnastępujący sposób.logs value of a = 10

var a = 1;
function b() {
  a = 10;  // overwrites the value of global 'var a'
  return;
}
b();
console.log(a); // logs a = 10

Obserwacja pomoże ci zrozumieć, że instrukcja console.log(a)rejestruje następujące wartości.

Przypadek 1: a = 1

Przypadek 2: a = 10

Pozycje

  1. var a został zdefiniowany i zadeklarowany leksykalnie w zakresie globalnym.
  2. a=10 Ta instrukcja ponownie przypisuje wartość do 10, leksykalnie znajduje się wewnątrz funkcji b.

Wyjaśnienie obu przypadków

Ponieważ function definition with name propertyjest to to samo, co variable a. variable aWewnątrz function body bstaje się zmienna lokalna. Z poprzedniego wiersza wynika, że ​​globalna wartość a pozostaje nienaruszona, a lokalna wartość a jest aktualizowana do 10.

Tak więc zamierzamy powiedzieć, że poniższy kod

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Jest interpretowany przez interpreter JS w następujący sposób.

var a = 1;
function b() {
  function a() {}
  a = 10;
  return;


}
b();
console.log(a); // logs a = 1

Jednak gdy usuniemy deklarację function a(){} definition, value of 'a'zadeklarowaną i zdefiniowaną poza funkcją b, ta wartość zostanie nadpisana i zmieni się na 10 w przypadku 2. Wartość zostanie nadpisana, ponieważ a=10odnosi się do deklaracji globalnej i jeśli miała być zadeklarowana lokalnie, musimy mieć napisane var a = 10;.

var a = 1;
function b() {
  var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;
}
b();
console.log(a); // logs a = 1

Możemy wyjaśnić nasze wątpliwości dodatkowo zmieniając name propertyin function a(){} definitiondo innej nazwy niż'a'

var a = 1;
function b() {
  a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;

  function foo() {}
}
b();
console.log(a); // logs a = 1
Sagar Munjal
źródło
1

Podnoszenie to koncepcja stworzona dla nas, aby była łatwiejsza do zrozumienia. W rzeczywistości następuje to, że deklaracje są wykonywane jako pierwsze w odniesieniu do ich zakresów, a przypisania następują po tym (nie w tym samym czasie).

Kiedy deklaracje się zdarzają, var awtedy function bi wewnątrz tego bzakresu function ajest deklarowane.

Ta funkcja a będzie cieniać zmienną a pochodzącą z zasięgu globalnego.

Po wykonaniu deklaracji rozpocznie się przypisywanie wartości, globalny aotrzyma wartość, 1a a inside function botrzyma 10. kiedy to zrobisz alert(a), wywoła rzeczywistą zmienną o zasięgu globalnym. Ta niewielka zmiana w kodzie sprawi, że będzie on bardziej przejrzysty

        var a = 1;

    function b() {
        a = 10;
        return a;

        function a() { }
    }

    alert(b());
    alert(a);
Buzzzzzzz
źródło
1
To ciekawe, że tak wielu ekspertów, nawet na kursie na stronie codechool.com, odnosi się do podnoszenia, które jest niczym innym jak uproszczonym spojrzeniem na to, co się dzieje, a tak naprawdę podnoszenie w ogóle się nie dzieje. Ref: 1) developer.mozilla.org/en-US/docs/Glossary/Hoisting 2) Rozdział 5 Secrets of the JavaScript Ninja 2 / e autor: john resig, bear bebeault, josip maras
adnan 2
1

Zaskakujące jest, że żadna z odpowiedzi tutaj nie wspomina o znaczeniu kontekstu wykonania w łańcuchu zakresu.

JavaScript Engine opakowuje aktualnie wykonywany kod w kontekście wykonania. Podstawowym kontekstem wykonania jest globalny kontekst wykonania. Za każdym razem, gdy wywoływana jest nowa funkcja, tworzony jest nowy kontekst wykonania i umieszczany na stosie wykonywania. Pomyśl o ramce stosu znajdującej się na stosie wywołań w innych językach programowania. Ostatni w pierwszym na wyjściu. Teraz każdy kontekst wykonania ma własne środowisko zmienne i środowisko zewnętrzne w JavaScript.

Jako demonstrację posłużę się poniższym przykładem.

1) Najpierw wchodzimy w fazę tworzenia globalnego kontekstu wykonania. Tworzone jest zarówno środowisko zewnętrzne, jak i zmienne środowisko leksykalne. Obiekt globalny jest ustawiany i umieszczany w pamięci ze specjalną zmienną „this” wskazującą na niego. Funkcja a i jej kod oraz zmienna myVar z niezdefiniowaną wartością są umieszczane w pamięci globalnego środowiska zmiennych. Należy zauważyć, że kod funkcji a nie jest wykonywany. Jest po prostu umieszczany w pamięci z funkcją a.

2) Po drugie, jest to faza wykonania kontekstu wykonania. myVar nie jest już nieokreśloną wartością. Jest inicjalizowany wartością 1, która jest przechowywana w globalnym środowisku zmiennych. Funkcja a jest wywoływana i tworzony jest nowy kontekst wykonania.

3) W kontekście wykonania funkcji a przechodzi przez fazę tworzenia i wykonywania własnego kontekstu wykonania. Ma swoje własne środowisko zewnętrzne i zmienne środowisko, a zatem własne środowisko leksykalne. Funkcja b i zmienna myVar są przechowywane w jej zmiennym środowisku. To środowisko zmienne różni się od globalnego środowiska zmiennego. Ponieważ funkcja a znajduje się leksykalnie (fizycznie w kodzie) na tym samym poziomie co globalny kontekst wykonania, jej środowisko zewnętrzne jest globalnym kontekstem wykonania. Tak więc, jeśli funkcja a miała odnosić się do zmiennej, która nie znajduje się w jej środowisku zmiennych, przeszuka łańcuch zakresu i spróbuje znaleźć zmienną w środowisku zmiennym globalnego kontekstu wykonania.

4) Funkcja b jest wywoływana w funkcji a. Tworzony jest nowy kontekst wykonania. Ponieważ znajduje się leksykalnie w funkcji a, jego środowisko zewnętrzne to a. Więc kiedy odwołuje się do myVar, ponieważ myVar nie znajduje się w zmiennym środowisku funkcji b, będzie wyglądać w zmiennym środowisku funkcji a. Znajduje ją tam i console.log wyświetla 2. Ale jeśli zmienna nie znajduje się w zmiennym środowisku funkcji a, to ponieważ środowisko zewnętrzne funkcji a jest globalnym kontekstem wykonania, wówczas łańcuch zakresu będzie tam kontynuował wyszukiwanie.

5) Po zakończeniu wykonywania funkcji b i a są one usuwane ze stosu wykonania. Jednowątkowy silnik JavaScript kontynuuje wykonywanie w globalnym kontekście wykonywania. Wywołuje funkcję b. Ale nie ma funkcji b w globalnym środowisku zmiennych i nie ma innego środowiska zewnętrznego do przeszukiwania w globalnym kontekście wykonania. W związku z tym silnik JavaScript zgłasza wyjątek.

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

Poniższy przykład pokazuje łańcuch zakresu w akcji. W środowisku zmiennych kontekstu wykonania funkcji b nie ma myVar. Więc przeszukuje swoje środowisko zewnętrzne, które jest funkcją a. Funkcja a także nie ma myVar w swoim zmiennym środowisku. Tak więc Silnik wyszukuje funkcję Środowisko zewnętrzne a, które jest globalnym środowiskiem zewnętrznym kontekstu wykonania, a myVar jest tam zdefiniowane. W związku z tym console.log wyświetla 1.

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 1

Jeśli chodzi o kontekst wykonania i związane z nim środowisko leksykalne, w tym środowisko zewnętrzne i środowisko zmienne, włącz określanie zakresu zmiennych w JavaScript. Nawet jeśli wywołasz tę samą funkcję wiele razy, dla każdego wywołania utworzy ona własny kontekst wykonania. Zatem każdy kontekst wykonania będzie miał własną kopię zmiennych w swoim środowisku zmiennych. Nie ma współdzielenia zmiennych.

Donato
źródło
0

Dzieje się tak, ponieważ nazwa zmiennej jest taka sama, jak nazwa funkcji oznacza „a”. Tak więc ze względu na podnoszenie Javascript próbuje rozwiązać konflikt nazw i zwróci a = 1.

Byłem tym zdezorientowany, dopóki nie przeczytałem tego posta na temat „JavaScript Hoisting” http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Mam nadzieję, że to pomoże.

AugustRush
źródło
0

Oto moje podsumowanie odpowiedzi z większą liczbą adnotacji i akompaniującymi skrzypcami do zabawy.

// hoisting_example.js

// top of scope ie. global var a = 1
var a = 1;

// new scope due to js' functional (not block) level scope
function b() {
    a = 10; // if the function 'a' didn't exist in this scope, global a = 10
  return; // the return illustrates that function 'a' is hoisted to top
  function a(){}; // 'a' will be hoisted to top as var a = function(){};
}

// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b' 
// and in doing so, created a new named variable 'a' 
// which is a function within b's scope
b();

// a will alert 1, see comment above
alert(a);

https://jsfiddle.net/adjavaherian/fffpxjx7/

4m1r
źródło
0

zakres i zamknięcie i podnoszenie (zmienna / funkcja)

  1. scpope: globalna zmienna może być dostępna w dowolnym miejscu (cały zasięg pliku), lokalna zmienna może być dostępna tylko przez lokalny zasięg (zakres funkcji / bloku)!
    Uwaga: jeśli zmienna lokalna nie używa słów kluczowych var w funkcji, stanie się zmienną globalną!
  2. zamknięcie: funkcja wewnątrz drugiej funkcji, która może uzyskać dostęp do zakresu lokalnego (funkcja nadrzędna) i zasięgu globalnego, niezależnie od tego, czy inni nie mają dostępu do jej zmiennych! chyba że zwrócisz go jako wartość zwracaną!
  3. podnoszenie: przenieś wszystkie deklarowane / nieokreślone zmienne / funkcje na górę zakresu, niż przypisz wartość lub null!
    Uwaga: po prostu przesuń deklarację, nie przesuwaj wartości!

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

xgqfrms
źródło
0

Podnoszenie W JavaScript oznacza, że ​​deklaracje zmiennych są wykonywane w całym programie przed wykonaniem jakiegokolwiek kodu. Dlatego zadeklarowanie zmiennej w dowolnym miejscu kodu jest równoznaczne z zadeklarowaniem jej na początku.

Vishwas SL
źródło
0

Wszystko zależy od zakresu zmiennej „a”. Pozwólcie, że wyjaśnię, tworząc zakresy jako obrazy.

Tutaj JavaScript utworzy 3 zakresy.

i) Zakres globalny. ii) Zakres funkcji b (). iii) Funkcja a () zakres.

wprowadź opis obrazu tutaj

Jest jasne, kiedy wywołujesz metodę „alert”, zakres należy w tym czasie do Global, więc wybierze wartość zmiennej „a” tylko z zakresu globalnego, czyli 1.

Sumit Pahuja
źródło
0

Długi post!

Ale to oczyści powietrze!

Sposób działania Java Script polega na tym, że obejmuje proces dwuetapowy:

  1. Kompilacja (że tak powiem) - ten krok rejestruje zmienne i deklaracje funkcji oraz ich odpowiedni zakres. Nie obejmuje wartościowania wyrażenia funkcyjnego: var a = function(){}ani wyrażenia zmiennego (jak przypisywanie 3do, xw przypadku var x =3;którego jest niczym innym jak oszacowaniem części RHS).

  2. Tłumacz: To jest część wykonania / oceny.

Sprawdź dane wyjściowe poniższego kodu, aby uzyskać zrozumienie:

//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);

function b() {
  //cannot write the below line:
  //console.log(e); 
  //since e is not declared.
  e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
  console.log("e is " + e) //  works!
  console.log("f is " + f);
  var f = 7;
  console.log("Now f is " + f);
  console.log("d is " + d);
  return;

  function d() {}
}
b();
console.log(a);

Przełammy to:

  1. Na etapie kompilacji „a” zostałoby zarejestrowane w zakresie globalnym z wartością „ undefined”. To samo dotyczy „ c”, jego wartością w tym momencie będzie „ undefined”, a nie „ function()”. „ b” zostałby zarejestrowany jako funkcja o zasięgu globalnym. Wewnątrz b„zakresu f” zostałaby zarejestrowana jako zmienna, która w tym momencie byłaby niezdefiniowana, a funkcja „ d” zostałaby zarejestrowana.

  2. Po uruchomieniu interpretera function()można uzyskać dostęp do zadeklarowanych zmiennych i (a nie wyrażeń), zanim interpreter osiągnie właściwy wiersz wyrażenia. Tak więc zmienne byłyby wypisywane ' undefined' i można wcześniej wywołać zadeklarowaną funkcję anonimową. Jednak próba uzyskania dostępu do niezadeklarowanej zmiennej przed zainicjalizowaniem jej wyrażenia spowodowałaby błąd, taki jak:

console.log(e)
e = 3;

Co się dzieje, gdy masz deklarację zmiennej i funkcji o tej samej nazwie.

Odpowiedź brzmi - funkcje są zawsze podnoszone przed i jeśli zadeklarowana jest zmienna o tej samej nazwie, jest ona traktowana jako zduplikowana i ignorowana. Pamiętaj, kolejność nie ma znaczenia. Funkcje zawsze mają pierwszeństwo. Ale podczas fazy oceny możesz zmienić odwołanie do zmiennej na cokolwiek (przechowuje to, co było ostatnim przypisaniem) Spójrz na poniższy kod:

var a = 1;
console.log("a is " + a);

function b() {
  console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
  a = 3; //a changed
  console.log("Now a is " + a);
  return;

  function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.

pragun
źródło
0

Podnoszenie to behawioralna koncepcja JavaScript. Podnoszenie (powiedzmy w ruchu) to koncepcja, która wyjaśnia, jak i gdzie należy zadeklarować zmienne.

W JavaScript zmienną można zadeklarować po jej użyciu, ponieważ deklaracje funkcji i deklaracje zmiennych są zawsze przenoszone („podnoszone”) w niewidoczny sposób na górę ich zakresu zawierającego przez interpreter JavaScript.

W większości przypadków mamy do czynienia z dwoma rodzajami podnoszenia.

1. Podnoszenie deklaracji zmiennych

Rozumiemy to na podstawie tego fragmentu kodu.

 a = 5; // Assign 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
 var a; // Declare a
  //output-> 5

W tym przypadku deklaracja zmiennej a będzie hostowana na górze niewidocznie przez interpreter javascript w czasie kompilacji. Więc byliśmy w stanie uzyskać wartość. Ale to podejście do deklaracji zmiennych nie jest zalecane, ponieważ powinniśmy już tak deklarować zmienne na górze.

 var a = 5; // Assign and declare 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
  // output -> 5

rozważ inny przykład.

  function foo() {
     console.log(x)
     var x = 1;
 }

jest właściwie interpretowane w ten sposób:

  function foo() {
     var x;
     console.log(x)
     x = 1;
  }

W tym przypadku x będzie niezdefiniowane

Nie ma znaczenia, czy wykonał się kod zawierający deklarację zmiennej. Rozważmy ten przykład.

  function foo() {
     if (false) {
         var a = 1;
     }
     return;
     var b = 1;
  }

Ta funkcja okazuje się taka.

  function foo() {
      var a, b;
      if (false) {
        a = 1;
     }
     return;
     b = 1;
  }

W deklaracji zmiennej podnoszone są tylko definicje zmiennych, a nie przypisanie.

  1. Podnoszenie deklaracji funkcji

W przeciwieństwie do zmiennej podnoszącej, korpus funkcji lub przypisana wartość również zostanie podniesiona. Rozważ ten kod

 function demo() {
     foo(); // this will give error because it is variable hoisting
     bar(); // "this will run!" as it is function hoisting
     var foo = function () {
         alert("this would not run!!");
     }
     function bar() { 
         alert("this will run!!");
     }
 }
 demo();

Teraz, gdy zrozumieliśmy zarówno podnoszenie zmiennych, jak i funkcji, zrozummy teraz ten kod.

var a = 1;
function b() {
  a = 10;
  return;
   function a() {}
}
b();
alert(a);

Ten kod okaże się taki.

var a = 1;                 //defines "a" in global scope
 function b() {  
   var a = function () {}; //defines "a" in local scope 
    a = 10;                 //overwrites local variable "a"
    return;      
 }       
 b();       
 alert(a); 

Funkcja a () będzie miała zasięg lokalny wewnątrz b (). a () zostanie przeniesiony na górę podczas interpretacji kodu z jego definicją (tylko w przypadku podnoszenia funkcji), więc a teraz będzie miał zasięg lokalny i dlatego nie wpłynie na globalny zasięg a, mając własny zakres wewnątrz funkcji b () .

Mustkeem K
źródło
0

Z mojej wiedzy, podnoszenie odbywa się z deklaracją zmiennej i deklaracją funkcji, na przykład:

a = 7;
var a;
console.log(a) 

Co dzieje się w silniku JavaScript:

var a;
a = 7;
console.log(a);
// 7

Lub:

console.log(square(7)); // Output: 49
function square(n) { return n * n; }

Stanie się:

function square(n) { return n * n; }
console.log(square(7)); // 49

Ale przypisania, takie jak przypisanie zmiennych, przypisanie wyrażenia funkcji nie zostaną podniesione: Na przykład:

console.log(x);
var x = 7; // undefined

Może wyglądać tak:

var x;
console.log(x); // undefined
x = 7;
Nam V. Do
źródło
0

Aby opisać hosting w javascript w jednym zdaniu, zmienne i funkcje są podnoszone na początek zakresu, w którym są zadeklarowane.

wprowadź opis obrazu tutaj

Zakładam, że jesteś początkującym, aby najpierw dobrze zrozumieć podnoszenie, zrozumieliśmy różnicę między undefined a ReferenceError

 var v;
 console.log(v);
 console.log(abc);
/*
The output of the above codes are:
undefined
ReferenceError: abc is not defined*/

teraz w kodzie poniżej, co widzimy? zmienna i wyrażenie funkcyjne jest decleard.

<script>
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
</script>

ale prawdziwy obraz z dowodem, że zarówno zmienna, jak i funkcja znajdują się na szczycie tego zakresu:

console.log(totalAmo);
console.log(getSum(8,9));
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
console.log(totalAmo);
console.log(getSum(9,7));

Dane wyjściowe pierwszych dwóch dzienników są niezdefiniowane, a TypeError: getSum nie jest funkcją, ponieważ zarówno var totalAmo, jak i getSum są umieszczone na szczycie zakresu, jak poniżej

 <script>
        var totalAmo;
        var getSum;

        console.log(totalAmo);
        console.log(getSum(8,9));
        var totalAmo = 8;
        var getSum = function(a, b){
            return a+b;
        }
        console.log(totalAmo);
        console.log(getSum(9,7));
    </script>

Ale w przypadku deklaracji funkcji całe funkcje zostały podniesione na szczycie ich zakresu.

console.log(getId());
function getId(){
   return 739373;
}
/* output: 739373, because the whole function hoisted on the top of the scope.*/

Teraz ta sama logika dotyczy tych wariacji, wyrażeń funkcji i deklaracji funkcji zadeklarowanych w zakresie funkcjonalnym. Kluczowa kwestia: nie będą podnoszone na górze pliku ;

function functionScope(){
            var totalAmo;
            var getSum;

            console.log(totalAmo);
            console.log(getSum(8,9));
            var totalAmo = 8;
            var getSum = function(a, b){
                return a+b;
            }
        }

Tak więc, gdy używasz słowa kluczowego var , zmiennej i funkcji podniesionych na górze zakresu (zakres globalny i zakres funkcji). A co z let i const , const i let nadal są świadome zasięgu globalnego i zakresu funkcji, podobnie jak var, ale zmienne const i let są również świadome innego zakresu zwanego zakresem blokowanym. zasięg blokowy jest obecny zawsze, gdy istnieje blok kodu, taki jak pętla for, instrukcja if else, pętla while itp.

Kiedy używamy const i pozwalamy zadeklarować zmienną w tym zakresie blokowym, deklaracja zmiennej zostanie podniesiona tylko na górę tego bloku, w którym się znajduje, i nie zostanie podniesiona na górę funkcji nadrzędnej lub górnej części zasięg globalny, że jest podnoszony.

 function getTotal(){
            let total=0;
            for(var i = 0; i<10; i++){
                let valueToAdd = i;
                var multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

Zmienne w powyższym przykładzie zostaną podniesione jak poniżej

 function getTotal(){
            let total;
            var multiplier;
            total = 0;
            for(var i = 0; i<10; i++){
                let valueToAdd;
                valueToAdd = i;
                multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }
Lord
źródło
0

ES5: funkcja podnoszenia i zmienne podnoszenie

function hoistingpriorytet jest greaterniżvariable hoisting

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2016-06-01
 * @modified
 *
 * @description function-hoisting.js
 * @augments
 * @example
 * @link
 *
 */

(function() {
  const log = console.log;

  var a = 1;
  function b() {
    a = 10;
    log(`local a`, a)
    return;
    // function hoisting priority is greater than variable hoisting
    function a() {}
  }
  b();
  log(`global a`, a);
  // local a 10
  // global a 1
})();



co jest równe

(function() {
  const log = console.log;

  // define "a" in global scope
  var a = 1;
  function b() {
    // define "a" in local scope
    var a ;
    // assign function to a
    a = function () {};
    // overwrites local variable "a"
    a = 10;
    log(`local a`, a);
    return;
  }

  b();
  // log global variable "a"
  log(`global a`, a);

  // local a 10
  // global a 1
})();

powód podnoszenia

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

/**
 *  scpope & closure & hoisting (var/function)
 *  
 * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
 * Note: if a local variable not using var keywords in a function, it will become a global variable!
 * 
 * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
 * 
 * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
 * Note: it just move the declare, not move the value!
 * 
 */

ES6 let, constnie ma podnoszenia

(() => {
  const log = console.log;
  log(a)
  // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1;
})();



(() => {
  const log = console.log;
  log(b)
  // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
  const b = 1;
})();

refs

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

xgqfrms
źródło