Omfang og tilslutning

I JavaScript er omfanget konteksten der koden er utført. Det er tre typer omfang: globalt omfang, lokalt omfang (noen ganger referert til som "funksjonsomfang") og eval-omfang.

Kode definert ved hjelp av Var Innenfor en funksjon er lokalt scoped, og er kun "synlig" til andre uttrykk i den funksjonen, som inkluderer kode inne i alle nestede / barnfunksjoner. Variabler definert i det globale omfanget kan nås fra hvor som helst fordi det er høyeste nivå og siste stopp i omfanget av kjeden.

Undersøk koden som følger og sørg for at du forstår at hver deklarasjon av foo er unikt på grunn av omfanget.

Eksempel: sample110.html

 

Pass på at du forstår at hver foo variabel inneholder en annen verdi fordi hver enkelt er definert i et spesifikt avgrenset omfang.

Et ubegrenset antall funksjons- og eval-mål kan opprettes, mens bare ett globalt omfang brukes av et JavaScript-miljø.

Det globale omfanget er det siste stoppet i omfanget av kjeden.

Funksjoner som inneholder funksjoner, oppretter stablede utførelsesområder. Disse stablene, som er sammenkalt, blir ofte referert til som omfangskjeden.


JavaScript har ikke blokkomfang

Siden logiske uttalelser (hvis) og looping uttalelser (til) Ikke opprett et omfang, variabler kan overskrive hverandre. Undersøk følgende kode og sørg for at du forstår at verdien av foo blir omdefinert når programmet kjører koden.

Eksempel: sample111.html

 

foo endrer seg etter hvert som koden kjøres fordi JavaScript ikke har noen blokkeringsfunksjon, global eller eval-rekkevidde.


Bruk Var Innsiden av funksjoner for å erklære variabler og unngå omfanget av Gotchas

JavaScript vil erklære eventuelle variabler som mangler a Var erklæring (selv de som finnes i en funksjon eller innkapslede funksjoner) for å være i det globale omfanget i stedet for det tiltenkte lokale omfanget. Ta en kikk på koden som følger og legg merke til det uten bruk av Var å erklære bar, er variabelen faktisk definert i det globale omfanget og ikke det lokale omfanget, hvor det skal være.

Eksempel: sample112.html

 

Konseptet å ta bort her er at du alltid bør bruke Var når du definerer variabler inne i en funksjon. Dette vil forhindre deg i å håndtere potensielt forvirrende omfangsproblemer. Unntaket fra denne konvensjonen er selvsagt når du vil opprette eller endre egenskaper i det globale omfanget fra en funksjon.


Omfangskjeden (aka Lexical Scoping)

Det er en oppslagskjede som følges når JavaScript ser etter verdien som er knyttet til en variabel. Denne kjeden er basert på omfanget av hierarkiet. I koden som følger, logger jeg verdien av sayHiText fra func2 funksjonsomfang.

Eksempel: sample113.html

 

Hvordan er verdien av sayHiText funnet når den ikke er inneholdt innenfor rammen av func2 funksjon? JavaScript ser først ut i func2 funksjon for en variabel som heter sayHiText. Ikke funnet func2 der ser det opp til func2s hovedfunksjon, func1. De sayHiText variabel finnes ikke i func1 omfang, heller, så JavaScript fortsetter så opp til det globale omfanget hvor sayHiText er funnet, på hvilket tidspunkt verdien av sayHiText er levert. Hvis sayHiText ikke blitt definert i det globale omfanget, udefinert ville ha blitt returnert av JavaScript.

Dette er et veldig viktig konsept å forstå. La oss undersøke et annet kodeeksempel, en hvor vi tar tre verdier fra tre forskjellige mål.

Eksempel: sample114.html

 

Verdien for z er lokal til Bar funksjon og konteksten der console.log er påkalt. Verdien for y er i den foo funksjon, som er forelder for bar (), og verdien for x er i det globale omfanget. Alle disse er tilgjengelige for Bar fungere via omfangskjeden. Pass på at du forstår de referansevariablene i Bar Funksjonen vil sjekke hele veien opp til omfangskæden for de refererte variablene.

Omfangskjeden, hvis du tenker på det, er ikke så forskjellig fra prototypekjeden. Begge er rett og slett en måte for en verdi å bli oppdaget ved å sjekke et systematisk og hierarkisk sett med steder.


Scope Chain Lookup returnerer den første funnet verdien

I kodesammenstillingen som følger, kalles en variabel x eksisterer i samme omfang som det undersøkes med console.log. Denne "lokale" verdien av x brukes, og man kan si at det skygger, eller masker, den identiske navnet x variabler funnet lenger opp i omfanget kjeden.

Eksempel: sample115.html

 

Husk at omfangsoppslaget avsluttes når variabelen er funnet i nærmeste tilgjengelige lenke i kjeden, selv om det samme variabelnavnet blir brukt lenger opp i kjeden.


Omfanget bestemmes under funksjonsdefinisjon, ikke invokasjon

Siden funksjoner bestemmer omfang og funksjoner kan sendes rundt akkurat som hvilken som helst JavaScript-verdi, kan man tro at dechifisering av omfangskæden er komplisert. Det er faktisk veldig enkelt. Omfangskæden er bestemt basert på plasseringen av en funksjon under definisjon, ikke under påkalling. Dette kalles også leksikalsk scoping. Tenk lenge og hardt om dette, siden de fleste snuble over det ofte i JavaScript-kode.

Omfangskjeden er opprettet før du påberoper en funksjon. På grunn av dette kan vi lage nedleggelser. For eksempel kan vi få en funksjon til å returnere en nestet funksjon til det globale omfanget, men vår funksjon kan fortsatt få tilgang til omfanget av foreldrefunksjonen via omfanget av kjeden. I følgende eksempel definerer vi en parentFunction som returnerer en anonym funksjon, og vi kaller den returnerte funksjonen fra det globale omfanget. Fordi vår anonyme funksjon ble definert som inneholdt inne i parentFunction, det har fortsatt tilgang til parentFunctions omfang når det påberopes. Dette kalles en lukning.

Eksempel: sample116.html

 

Ideen du burde ta bort her er at omfangskjeden bestemmes under definisjonen bokstavelig talt på samme måte som koden er skrevet. Passerer rundt funksjoner inne i koden din, vil ikke endre omfanget av kjeden.


Lukking er forårsaket av omfanget kjeden

Ta det du har lært om omfangskjeden og omfangsoppslaget fra denne artikkelen, og en lukking bør ikke være altfor komplisert å forstå. I den følgende prøven oppretter vi en funksjon som kalles countUpFromZero. Denne funksjonen returnerer faktisk en referanse til barnets funksjon som er inneholdt i den. Når dette barnets funksjon (nestet funksjon) er påkalt, har den fortsatt tilgang til foreldrefunksjonens omfang på grunn av omfanget av kjeden.

Eksempel: sample117.html

 

Hver gang countUpFromZero funksjonen er påkalt, den anonyme funksjonen som er inneholdt i (og returnert fra) countUpFromZero funksjonen har fortsatt tilgang til foreldrefunksjonens omfang. Denne teknikken, tilrettelagt via omfanget kjeden, er et eksempel på en lukning.


Konklusjon

Hvis du føler at jeg har overforenklet nedleggelse, er du sannsynligvis riktig i denne tanken. Men jeg gjorde det med vilje, da jeg tror de viktige delene kommer fra en solid forståelse av funksjoner og omfang, ikke nødvendigvis kompleksiteten i eksekveringssammenheng. Hvis du har behov for en grundig dykk i nedleggelser, ta en titt på JavaScript-lukninger.