I JavaScript är räckvidden det sammanhang där kod körs. Det finns tre typer av räckvidd: globalt räckvidd, lokalt räckvidd (ibland benämnt "funktionsomfång") och eval scope.
Kod definierad med var
Inne i en funktion är lokalt scoped, och är bara "synlig" för andra uttryck i den funktionen, som inkluderar kod inom alla kapslade / barnfunktioner. Variabler definierade i det globala räckviddet kan nås var som helst eftersom det är den högsta nivån och sista stoppet i omfångskedjan.
Undersök koden som följer och se till att du förstår att varje deklaration av foo
är unik på grund av omfattningen.
Prov: prov110.html
Se till att du förstår att var och en foo
variabeln innehåller ett annat värde eftersom var och en definieras i ett specifikt avgränsat räckvidd.
Ett obegränsat antal funktions- och eval-områden kan skapas, medan endast ett globalt räckvidd används av en JavaScript-miljö.
Det globala räckviddet är det sista stoppet i omfångskedjan.
Funktioner som innehåller funktioner skapar stabila utföringsfält. Dessa staplar, som är kedjda ihop, benämns ofta omfattningskedjan.
Eftersom logiska uttalanden (om
) och looping uttalanden (för
) skapar inte en räckvidd, variabler kan skriva över varandra. Undersök följande kod och se till att du förstår att värdet av foo
omdefinieras när programmet kör koden.
Prov: sample111.html
Så foo
ändras när koden körs, eftersom JavaScript inte har någon funktion för funktionalitet, endast globalt eller eval.
var
Inne i funktioner för att deklarera variabler och undvika omfattning GotchasJavaScript kommer att förklara några variabler som saknar a var
deklaration (även de som ingår i en funktion eller inkapslade funktioner) att vara i det globala räckviddet istället för det avsedda lokala räckviddet. Titta på koden som följer och märka det utan att använda var
att deklarera streck är variabeln faktiskt definierad i det globala räckviddet och inte den lokala räckvidden, där den borde vara.
Prov: prov112.html
Konceptet att ta bort här är att du alltid ska använda var
när man definierar variabler inuti en funktion. Detta kommer att förhindra att du hanterar potentiellt förvirrande räckviddsproblem. Undantaget från denna konvention är naturligtvis när du vill skapa eller ändra egenskaper i det globala räckviddet från en funktion.
Det finns en uppslagskedja som följs när JavaScript letar efter värdet associerat med en variabel. Denna kedja är baserad på omfattningen av hierarkin. I koden som följer loggar jag värdet på sayHiText
från func2
funktionens omfattning.
Prov: sample113.html
Hur är värdet av sayHiText
hittade när det inte finns inne i ramen för func2
fungera? JavaScript ser först ut i func2
funktion för en variabel som heter sayHiText
. Inte hitta func2
där ser det upp till func2
s föräldrafunktion, FUNC1
. De sayHiText
variabel finns inte i FUNC1
omfattning, antingen, så JavaScript fortsätter så upp till det globala räckvidd där sayHiText
hittas, vid vilken tidpunkt värdet av sayHiText
är levererad. Om sayHiText
hade inte definierats i det globala räckviddet, odefinierad
skulle ha returnerats av JavaScript.
Detta är ett mycket viktigt begrepp att förstå. Låt oss undersöka ett annat kodexempel där vi tar tre värden från tre olika områden.
Prov: sample114.html
Värdet för z
är lokal till bar
funktion och det sammanhang där console.log
åberopas. Värdet för y
är i foo
funktion, som är förälder till bar()
, och värdet för x
är i global omfattning. Alla dessa är tillgängliga för bar
funktion via omfattningskedjan. Se till att du förstår de referensvariablerna i bar
funktionen kommer att kontrollera hela vägen för kedjan för variablerna som refereras.
Omfattningskedjan, om du tänker på det, är inte så annorlunda än prototypkedjan. Båda är helt enkelt ett sätt att värdera ett värde genom att kontrollera en systematisk och hierarkisk uppsättning platser.
I det kodprov som följer, kallas en variabel x
existerar inom samma räckvidd som det undersöks med console.log
. Detta "lokala" värde av x
används, och man kan säga att det skuggar, eller maskerar, den identiska namnet x
variablerna hittades längre fram inom ramen för kedjan.
Prov: sample115.html
Kom ihåg att scope lookup slutar när variabeln finns i närmaste tillgängliga länk i kedjan, även om samma variabla namn används vidare upp i kedjan.
Eftersom funktioner bestämmer räckvidd och funktioner kan överföras precis som vilket som helst JavaScript-värde kan man tro att dechiffreringen av omfattningskedjan är komplicerad. Det är faktiskt väldigt enkelt. Omfattningskedjan bestäms utifrån placeringen av en funktion under definitionen, inte under invokation. Detta kallas också lexical scoping. Tänk lång och svårt om detta, eftersom de flesta ofta snubblar över det i JavaScript-kod.
Omfattningskedjan skapas innan du påbereder en funktion. På grund av detta kan vi skapa nedläggningar. Till exempel kan vi få en funktion att returnera en kapslad funktion till det globala räckviddet, men vår funktion kan fortfarande, via omfattningskedjan, få tillgång till dess överordnade funktion. I följande exempel definierar vi a parentFunction
som returnerar en anonym funktion, och vi kallar den returnerade funktionen från det globala räckviddet. Eftersom vår anonyma funktion definierades som innehöll inuti parentFunction
, det har fortfarande tillgång till parentFunctions
räckvidd när det åberopas. Detta kallas en nedläggning.
Prov: sample116.html
Tanken att du ska ta bort här är att omfångskedjan bestäms vid definitionen bokstavligen i det sätt som koden skrivs. Om du skickar in funktioner inom din kod ändras inte omfattningskedjan.
Ta det du har lärt dig om omfattningen kedjan och omfånget lookup från den här artikeln, och en stängning bör inte vara alltför komplicerad att förstå. I följande exempel skapar vi en funktion som heter countUpFromZero
. Den här funktionen returnerar faktiskt en referens till barnfunktionen i den. När detta barns funktion (nestad funktion) åberopas, har den fortfarande tillgång till moderfunktionens omfattning på grund av omfattningskedjan.
Prov: sample117.html
Varje gång countUpFromZero
funktionen åberopas, den anonyma funktionen som finns i (och återvände från) countUpFromZero
funktionen har fortfarande tillgång till moderfunktionens omfattning. Denna teknik, underlättad via omfattningskedjan, är ett exempel på en tillslutning.
Om du känner att jag har förenklade stängningar, är du troligt korrekt i den här tanken. Men jag gjorde det med avsikt eftersom jag tror att de viktiga delarna kommer från en solid förståelse av funktioner och omfattning, inte nödvändigtvis komplexiteten i exekveringssammanhang. Om du behöver ett djupt dykk i stängningar, ta en titt på JavaScript-stängningar.