Campo di applicazione e chiusure

In JavaScript, scope è il contesto in cui viene eseguito il codice. Esistono tre tipi di ambito: ambito globale, ambito locale (a volte indicato come "ambito di funzione") e ambito di valutazione.

Codice definito usando var all'interno di una funzione è localmente ambito ed è solo "visibile" ad altre espressioni in quella funzione, che include il codice all'interno di qualsiasi funzione nidificata / secondaria. È possibile accedere alle variabili definite nello scope globale da qualsiasi luogo poiché è il livello più alto e l'ultimo arresto nella catena dell'ambito.

Esamina il codice che segue e assicurati di aver compreso che ogni dichiarazione di foo è unico a causa dell'ambito.

Esempio: sample110.html

 

Assicurati di averlo compreso foo variabile contiene un valore diverso perché ognuno è definito in un ambito delimitato in modo specifico.

È possibile creare un numero illimitato di funzioni ed ambiti di valutazione, mentre un solo ambito globale viene utilizzato da un ambiente JavaScript.

L'ambito globale è l'ultimo arresto nella catena di portata.

Le funzioni che contengono funzioni creano ambiti di esecuzione impilati. Queste pile, che sono incatenate insieme, sono spesso indicate come la catena di portata.


JavaScript non ha un ambito di blocco

Poiché le istruzioni logiche (Se) e istruzioni loop (per) non creare un ambito, le variabili possono sovrascrivere l'un l'altro. Esamina il seguente codice e assicurati di aver compreso il valore di foo viene ridefinito mentre il programma esegue il codice.

Esempio: sample111.html

 

Così foo sta cambiando mentre il codice viene eseguito perché JavaScript non ha scope scope, global o scope solo scope.


Uso var All'interno delle funzioni per dichiarare le variabili ed evitare i trucchi di ambito

JavaScript dichiarerà qualsiasi variabile mancante di a var dichiarazione (anche quelli contenuti in una funzione o funzioni incapsulate) di essere nello scope globale invece dell'ambito locale previsto. Dai un'occhiata al codice che segue e notalo senza l'uso di var per dichiarare la barra, la variabile viene effettivamente definita nell'ambito globale e non l'ambito locale, dove dovrebbe essere.

Esempio: sample112.html

 

Il concetto da portare via qui è che dovresti sempre usare var quando si definiscono le variabili all'interno di una funzione. Ciò ti impedirà di affrontare problemi di oscillazione potenzialmente confusi. L'eccezione a questa convenzione, ovviamente, è quando si desidera creare o modificare proprietà nello scope globale da una funzione.


The Scope Chain (alias Lexical Scoping)

C'è una catena di ricerca che viene seguita quando JavaScript cerca il valore associato a una variabile. Questa catena si basa sulla gerarchia dello scopo. Nel codice che segue, sto registrando il valore di sayHiText dal funz2 ambito di funzione.

Esempio: sample113.html

 

Come è il valore di sayHiText trovato quando non è contenuto all'interno dell'ambito del funz2 funzione? JavaScript guarda prima nel funz2 funzione per una variabile denominata sayHiText. Non trovando funz2 lì, guarda in alto funz2s funzione genitore, FUNC1. Il sayHiText variabile non si trova nel FUNC1 ambito, quindi, quindi JavaScript continua fino all'ambito globale in cui sayHiText viene trovato, a quel punto il valore di sayHiText è consegnato. Se sayHiText non era stato definito nell'ambito globale, non definito sarebbe stato restituito da JavaScript.

Questo è un concetto molto importante da capire. Esaminiamo un altro esempio di codice, uno in cui prendiamo tre valori da tre diversi ambiti.

Esempio: sample114.html

 

Il valore per z è locale al bar funzione e il contesto in cui il console.log è invocato. Il valore per y è nel foo funzione, che è il genitore di bar(), e il valore per X è nella portata globale. Tutti questi sono accessibili al bar funzione tramite la catena di portata. Assicurati di aver capito che le variabili di riferimento nel bar la funzione controllerà tutta la catena dell'ambito per le variabili a cui si fa riferimento.

La catena dell'ambito, se ci pensate, non è molto diversa dalla catena del prototipo. Entrambi sono semplicemente un modo per cercare un valore controllando un insieme sistematico e gerarchico di posizioni.


La ricerca della catena dell'ambito restituisce il primo valore trovato

Nell'esempio di codice che segue, viene chiamata una variabile X esiste nello stesso ambito in cui viene esaminato console.log. Questo valore "locale" di X è usato, e si potrebbe dire che ombreggia, o maschere, il nome identico X variabili trovate più in alto nella catena dell'ambito.

Esempio: sample115.html

 

Ricorda che la ricerca dell'ambito termina quando la variabile viene trovata nel link disponibile più vicino della catena, anche se lo stesso nome della variabile viene utilizzato più in alto nella catena.


L'ambito è determinato durante la definizione della funzione, non il richiamo

Poiché le funzioni determinano lo scope e le funzioni possono essere passate come qualsiasi valore JavaScript, si potrebbe pensare che la decifrazione della catena di ambito sia complicata. In realtà è molto semplice. La catena dell'ambito viene decisa in base all'ubicazione di una funzione durante la definizione, non durante l'invocazione. Questo è anche chiamato scope lessicale. Pensaci a lungo, poiché la maggior parte delle persone ci si imbatte spesso in codice JavaScript.

La catena dell'ambito viene creata prima di richiamare una funzione. Per questo motivo possiamo creare chiusure. Ad esempio, possiamo avere una funzione che restituisce una funzione nidificata all'ambito globale, tuttavia la nostra funzione può ancora accedere, tramite la catena dell'ambito, all'ambito della sua funzione genitore. Nel seguente esempio, definiamo a parentFunction che restituisce una funzione anonima e chiamiamo la funzione restituita dall'ambito globale. Perché la nostra funzione anonima era definita come contenuta all'interno di parentFunction, ha ancora accesso a parentFunctions ambito quando viene invocato. Questo è chiamato una chiusura.

Esempio: sample116.html

 

L'idea che dovresti togliere qui è che la catena dell'ambito viene determinata durante la definizione letteralmente nel modo in cui il codice è scritto. Passare le funzioni all'interno del codice non cambierà la catena dell'ambito.


Le chiusure sono causate dalla catena di portata

Prendi ciò che hai imparato sulla catena di portata e la ricerca dell'ambito da questo articolo, e una chiusura non dovrebbe essere eccessivamente complicata da comprendere. Nel seguente esempio, creiamo una funzione chiamata countUpFromZero. Questa funzione restituisce effettivamente un riferimento alla funzione figlio contenuta al suo interno. Quando viene invocata questa funzione figlio (funzione nidificata), ha ancora accesso all'ambito della funzione genitore a causa della catena dell'ambito.

Esempio: sample117.html

 

Ogni volta il countUpFromZero viene invocata la funzione, la funzione anonima contenuta nel (e restituita da) il countUpFromZero la funzione ha ancora accesso all'ambito della funzione genitore. Questa tecnica, facilitata dalla catena dell'ambito, è un esempio di chiusura.


Conclusione

Se ritieni di avere chiusure eccessivamente semplificate, probabilmente hai ragione in questo pensiero. Ma l'ho fatto di proposito perché ritengo che le parti importanti derivino da una solida comprensione delle funzioni e dello scopo, non necessariamente dalla complessità del contesto di esecuzione. Se hai bisogno di approfondire le chiusure, dai un'occhiata alle chiusure JavaScript.