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.
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.
var
All'interno delle funzioni per dichiarare le variabili ed evitare i trucchi di ambitoJavaScript 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.
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 funz2
s 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.
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.
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.
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.
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.