Qual è l'ambito delle variabili in JavaScript?


2013

Qual è l'ambito delle variabili in JavaScript? Hanno lo stesso scopo all'interno anziché all'esterno di una funzione? O importa? Inoltre, dove sono memorizzate le variabili se sono definite a livello globale?


4
Ecco un altro bel link per tenere presente questo problema: " Spiegare l'ambito e le chiusure JavaScript ".
Software Engineer Full-Stack,

9
Ecco un articolo che lo spiega molto bene. Tutto ciò che devi sapere sull'ambito variabile Javascript
Saurab Parakh

2
L' e-book di Kyle Simpson precedentemente citato è disponibile per la lettura su Github e ti dice tutto ciò che devi sapere su Scopi e chiusure JavaScript. Puoi trovarlo qui: github.com/getify/You-Dont-Know-JS/blob/master/… Fa parte della serie di libri "Non conosci JS" , che è ottimo per tutti coloro che vorrebbero sapere altro su JavaScript.
3rik82,

Risposte:


2536

TLDR

JavaScript ha scopi e chiusure lessicali (chiamati anche statici). Ciò significa che puoi capire l'ambito di un identificatore guardando il codice sorgente.

I quattro ambiti sono:

  1. Globale - visibile da tutto
  2. Funzione: visibile all'interno di una funzione (e delle sue sotto-funzioni e blocchi)
  3. Blocco: visibile all'interno di un blocco (e dei suoi blocchi secondari)
  4. Modulo: visibile all'interno di un modulo

Al di fuori dei casi speciali di ambito globale e di modulo, le variabili vengono dichiarate utilizzando var(ambito funzione), let(ambito blocco) e const(ambito blocco). La maggior parte delle altre forme di dichiarazione dell'identificatore ha l'ambito del blocco in modalità rigorosa.

Panoramica

L'ambito è l'area della base di codice su cui è valido un identificatore.

Un ambiente lessicale è una mappatura tra i nomi degli identificatori e i valori ad essi associati.

L'ambito è formato da un annidamento collegato di ambienti lessicali, con ogni livello nell'annidamento corrispondente a un ambiente lessicale di un contesto di esecuzione degli antenati.

Questi ambienti lessicali collegati formano una "catena" di ambito. La risoluzione dell'identificatore è il processo di ricerca lungo questa catena per un identificatore corrispondente.

La risoluzione dell'identificatore si verifica solo in una direzione: verso l'esterno. In questo modo, gli ambienti lessicali esterni non possono "vedere" negli ambienti lessicali interni.

Esistono tre fattori pertinenti nel decidere l' ambito di un identificatore in JavaScript:

  1. Come è stato dichiarato un identificatore
  2. Dove è stato dichiarato un identificatore
  3. Che tu sia in modalità rigorosa o non rigorosa

Alcuni dei modi in cui gli identificatori possono essere dichiarati:

  1. var, leteconst
  2. Parametri di funzione
  3. Parametro blocco cattura
  4. Dichiarazioni di funzione
  5. Espressioni di funzioni denominate
  6. Proprietà definite implicitamente sull'oggetto globale (es. Perdita varin modalità non rigorosa)
  7. import dichiarazioni
  8. eval

Alcuni identificatori di località possono essere dichiarati:

  1. Contesto globale
  2. Corpo funzione
  3. Blocco ordinario
  4. La parte superiore di una struttura di controllo (ad esempio loop, if, while etc)
  5. Corpo della struttura di controllo
  6. moduli

Stili di dichiarazione

var

Gli identificatori dichiarati utilizzando var hanno un ambito di funzione , a parte quando vengono dichiarati direttamente nel contesto globale, nel qual caso vengono aggiunti come proprietà sull'oggetto globale e hanno un ambito globale. Esistono regole separate per il loro utilizzo nelle evalfunzioni.

let e const

Gli identificatori dichiarati utilizzando lete const hanno un ambito di blocco , a parte quando vengono dichiarati direttamente nel contesto globale, nel qual caso hanno un ambito globale.

Nota: let, conste var sono tutti issato . Ciò significa che la loro posizione logica di definizione è la parte superiore del loro ambito di applicazione (blocco o funzione). Tuttavia, le variabili dichiarate in uso lete constnon possono essere lette o assegnate fino a quando il controllo non ha superato il punto di dichiarazione nel codice sorgente. Il periodo intermedio è noto come zona morta temporale.

function f() {
    function g() {
        console.log(x)
    }
    let x = 1
    g()
}
f() // 1 because x is hoisted even though declared with `let`!

Nomi dei parametri delle funzioni

I nomi dei parametri delle funzioni sono assegnati al corpo della funzione. Si noti che c'è una leggera complessità in questo. Le funzioni dichiarate come argomenti predefiniti si chiudono sull'elenco dei parametri e non sul corpo della funzione.

Dichiarazioni di funzione

Le dichiarazioni di funzione hanno ambito di blocco in modalità rigorosa e ambito di funzione in modalità non rigorosa. Nota: la modalità non rigorosa è un insieme complicato di regole emergenti basate sulle stravaganti implementazioni storiche di diversi browser.

Espressioni di funzioni denominate

Le espressioni di funzioni denominate sono mirate a se stesse (ad es. Ai fini della ricorsione).

Proprietà definite implicitamente sull'oggetto globale

In modalità non rigorosa, le proprietà implicitamente definite sull'oggetto globale hanno ambito globale, poiché l'oggetto globale si trova nella parte superiore della catena dell'ambito. In modalità rigorosa non sono consentiti.

eval

Nelle evalstringhe, le variabili dichiarate utilizzando varverranno inserite nell'ambito corrente o, se evalutilizzate indirettamente, come proprietà dell'oggetto globale.

Esempi

Quanto segue gettare un ReferenceError perché i nomi x, ye znon hanno alcun significato al di fuori della funzione f.

function f() {
    var x = 1
    let y = 1
    const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)

Quanto segue genererà un ReferenceError per ye z, ma non per x, perché la visibilità di xnon è limitata dal blocco. I blocchi che definiscono i corpi di strutture di controllo come if, fore while, allo stesso modo si comportano.

{
    var x = 1
    let y = 1
    const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope

Di seguito, xè visibile al di fuori del ciclo perché varha ambito di funzione:

for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)

... a causa di questo comportamento devi stare attento a chiudere le variabili dichiarate usando var nei cicli. C'è solo un'istanza di variabile xdichiarata qui, e si trova logicamente fuori dal ciclo.

Le seguenti stampe 5, cinque volte, quindi stampa 5per la sesta volta per l' console.logesterno del ciclo:

for(var x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop

Di seguito viene stampato undefinedperché xè a blocchi. I callback vengono eseguiti uno alla volta in modo asincrono. Un nuovo comportamento per le letvariabili significa che ogni funzione anonima si è chiusa su una diversa variabile denominata x(diversamente da come avrebbe fatto con var), e così vengono stampati gli interi 0attraverso 4.:

for(let x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined

Quanto segue NON genererà a ReferenceErrorperché la visibilità di xnon è limitata dal blocco; verrà comunque stampato undefinedperché la variabile non è stata inizializzata (a causa ifdell'istruzione).

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

Una variabile dichiarata nella parte superiore di un forciclo che utilizza letè associata al corpo del ciclo:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

Quanto segue lancerà a ReferenceErrorperché la visibilità di xè limitata dal blocco:

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Le variabili dichiarate utilizzando var, leto constsono tutti scope ai moduli:

// module1.js

var x = 0
export function f() {}

//module2.js

import f from 'module1.js'

console.log(x) // throws ReferenceError

Quanto segue dichiarerà una proprietà sull'oggetto globale, poiché le variabili dichiarate usando varnel contesto globale, vengono aggiunte come proprietà all'oggetto globale:

var x = 1
console.log(window.hasOwnProperty('x')) // true

lete constnel contesto globale non aggiungere proprietà all'oggetto globale, ma hanno comunque portata globale:

let x = 1
console.log(window.hasOwnProperty('x')) // false

I parametri della funzione possono essere considerati dichiarati nel corpo della funzione:

function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function

I parametri del blocco di cattura sono definiti nel corpo del blocco di cattura:

try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block

Le espressioni di funzioni con nome hanno un ambito solo per l'espressione stessa:

(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression

In modalità non rigorosa, le proprietà implicitamente definite sull'oggetto globale sono di ambito globale. In modalità rigorosa viene visualizzato un errore.

x = 1 // implicitly defined property on the global object (no "var"!)

console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true

In modalità non rigorosa, le dichiarazioni di funzione hanno ambito di funzione. In modalità rigorosa hanno ambito di blocco.

'use strict'
{
    function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped

Come funziona sotto il cofano

L'ambito è definito come la regione lessicale del codice su cui è valido un identificatore.

In JavaScript, ogni oggetto-funzione ha un [[Environment]]riferimento nascosto che è un riferimento all'ambiente lessicale del contesto di esecuzione (stack frame) all'interno del quale è stato creato.

Quando si richiama una funzione, [[Call]]viene chiamato il metodo nascosto . Questo metodo crea un nuovo contesto di esecuzione e stabilisce un collegamento tra il nuovo contesto di esecuzione e l'ambiente lessicale dell'oggetto funzione. Lo fa copiando il [[Environment]]valore sull'oggetto funzione, in un riferimento esterno campo di nell'ambiente lessicale del nuovo contesto di esecuzione.

Si noti che questo collegamento tra il nuovo contesto di esecuzione e l'ambiente lessicale dell'oggetto funzione è chiamato chiusura .

Pertanto, in JavaScript, l'ambito viene implementato tramite ambienti lessicali collegati tra loro in una "catena" da riferimenti esterni. Questa catena di ambienti lessicali è chiamata catena dell'ambito e la risoluzione dell'identificatore si verifica cercando nella catena un identificatore corrispondente.

Per saperne di più .


280
Nemmeno vicino ad essere esaustivo, ma questo è forse l'insieme di trucchi dell'ambito Javascript che è necessario conoscere per poter effettivamente leggere il javascript moderno.
Trittico

148
Una risposta molto apprezzata, non so perché. È solo un mucchio di esempi senza una spiegazione adeguata, quindi sembra confondere l'ereditarietà del prototipo (ovvero la risoluzione delle proprietà) con la catena dell'ambito (ovvero la risoluzione variabile). Una spiegazione completa (e accurata) dell'ambito e della risoluzione delle proprietà è nelle note FAQ di comp.lang.javascript .
RobG

109
@RobG È molto apprezzato perché è utile e comprensibile per una vasta gamma di programmatori, nonostante la catacresca minore. Il link che hai pubblicato, sebbene utile per alcuni professionisti, è incomprensibile per la maggior parte delle persone che scrivono Javascript oggi. Sentiti libero di risolvere eventuali problemi di nomenclatura modificando la risposta.
Trittico,

7
@ trittico: modifico solo le risposte per correggere cose minori, non importanti. La modifica di "scope" in "property" risolverà l'errore, ma non il problema di mescolare ereditarietà e scope senza una chiara distinzione.
RobG

24
Se si definisce una variabile nell'ambito esterno e si dispone di un'istruzione if definire una variabile all'interno della funzione con lo stesso nome, anche se quel ramo non raggiunto viene ridefinito. Un esempio - jsfiddle.net/3CxVm
Chris S,

233

Javascript utilizza le catene dell'ambito per stabilire l'ambito di una determinata funzione. In genere esiste un ambito globale e ogni funzione definita ha il proprio ambito nidificato. Qualsiasi funzione definita all'interno di un'altra funzione ha un ambito locale collegato alla funzione esterna. È sempre la posizione nella fonte che definisce l'ambito.

Un elemento nella catena dell'ambito è fondamentalmente una mappa con un puntatore al suo ambito padre.

Quando si risolve una variabile, javascript inizia nell'ambito più interno e cerca verso l'esterno.


1
Le catene di portata sono un altro termine per chiusure [memoria] ... per coloro che leggono qui per imparare / entrare in JavaScript.
Nuova Alessandria,

108

Le variabili dichiarate a livello globale hanno un ambito globale. Le variabili dichiarate all'interno di una funzione hanno come ambito quella funzione e ombreggiano variabili globali con lo stesso nome.

(Sono sicuro che ci sono molte sottigliezze che i veri programmatori JavaScript saranno in grado di indicare in altre risposte. In particolare mi sono imbattuto in questa pagina su cosa thissignifica esattamente in qualsiasi momento. Spero che questo link più introduttivo sia sufficiente per iniziare però .)


7
Ho paura persino di iniziare a rispondere a questa domanda. Come programmatore Javascript reale, so quanto velocemente la risposta potrebbe sfuggire di mano. Bei articoli.
Trittico

10
@Triptych: so cosa intendi per cose che sfuggono di mano, ma per favore aggiungi comunque una risposta. Ho ottenuto quanto sopra solo facendo un paio di ricerche ... una risposta scritta da qualcuno con esperienza reale è destinata a essere migliore. Per favore, correggi qualsiasi mia risposta che è decisamente sbagliata!
Jon Skeet,

4
Jon Skeet è in qualche modo responsabile della MIA risposta più popolare su Stack Overflow.
Trittico

75

JavaScript della vecchia scuola

Tradizionalmente, JavaScript ha davvero solo due tipi di ambito:

  1. Ambito globale : le variabili sono note in tutta l'applicazione, dall'inizio dell'applicazione (*)
  2. Ambito funzionale : le variabili sono note all'interno della funzione in cui sono dichiarate, dall'inizio della funzione (*)

Non approfondirò questo aspetto, poiché ci sono già molte altre risposte che spiegano la differenza.


JavaScript moderno

Le specifiche JavaScript più recenti ora consentono anche un terzo ambito:

  1. Ambito del blocco : gli identificatori sono "conosciuti" dalla parte superiore dell'ambito in cui sono dichiarati , ma non possono essere assegnati o non riferiti (letti) fino a dopo la riga della loro dichiarazione. Questo periodo intermedio è chiamato "zona morta temporale".

Come si creano le variabili dell'ambito del blocco?

Tradizionalmente, crei le tue variabili in questo modo:

var myVariable = "Some text";

Le variabili dell'ambito del blocco vengono create in questo modo:

let myVariable = "Some text";

Quindi qual è la differenza tra ambito funzionale e ambito di blocco?

Per comprendere la differenza tra ambito funzionale e ambito del blocco, considerare il codice seguente:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Qui, possiamo vedere che la nostra variabile jè nota solo nel primo ciclo, ma non prima e dopo. Tuttavia, la nostra variabile iè nota nell'intera funzione.

Inoltre, considerare che le variabili con ambito di blocco non sono note prima di essere dichiarate perché non vengono issate. Inoltre, non è possibile dichiarare nuovamente la stessa variabile con ambito blocco all'interno dello stesso blocco. Ciò rende le variabili con ambito di blocco meno soggette a errori rispetto alle variabili con ambito globale o funzionale, che vengono sollevate e che non generano errori in caso di dichiarazioni multiple.


È sicuro utilizzare le variabili dell'ambito dei blocchi oggi?

L'utilizzo sicuro o meno oggi dipende dal tuo ambiente:

  • Se stai scrivendo codice JavaScript sul lato server ( Node.js ), puoi tranquillamente utilizzare l' letistruzione.

  • Se stai scrivendo un codice JavaScript sul lato client e usi un transpiler basato su browser (come Traceur o babel-standalone ), puoi tranquillamente utilizzare l' letistruzione, tuttavia è probabile che il tuo codice sia tutt'altro che ottimale rispetto alle prestazioni.

  • Se stai scrivendo codice JavaScript sul lato client e usi un transpiler basato su Nodo (come lo script della shell traceur o Babel ), puoi tranquillamente usare l' letistruzione. E poiché il tuo browser conoscerà solo il codice traspilato, gli svantaggi delle prestazioni dovrebbero essere limitati.

  • Se stai scrivendo codice JavaScript lato client e non usi un transpiler, devi considerare il supporto del browser.

    Questi sono alcuni browser che non supportano letaffatto:

    • Internet Explorer 10 e precedenti
    • Firefox 43 e versioni precedenti
    • Safari 9 e versioni precedenti
    • Browser Android 4 e precedenti
    • Opera 27 e precedenti
    • Chome 40 e sotto
    • QUALSIASI versione di Opera Mini e Blackberry Browser

inserisci qui la descrizione dell'immagine


Come tenere traccia del supporto del browser

Per una panoramica aggiornata di quali browser supportano la letdichiarazione al momento della lettura di questa risposta, consultare questa Can I Usepagina .


(*) Le variabili con portata globale e funzionale possono essere inizializzate e utilizzate prima di essere dichiarate perché le variabili JavaScript vengono issate . Ciò significa che le dichiarazioni sono sempre in cima all'ambito.


2
"NON È noto" è fuorviante, perché la variabile viene dichiarata lì a causa di un sollevamento.
Oriol,

L'esempio sopra è fuorviante, le variabili 'i' e 'j' non sono note al di fuori del blocco. Le variabili "Let" hanno ambito solo in quel particolare blocco non esterno al blocco. Consentiamo anche di altri vantaggi, non è possibile dichiarare nuovamente la variabile e mantenere l'ambito lessicale.
zakir,

1
Questo è stato utile, grazie! Penso che sarebbe ancora più utile essere specifici su cosa intendi con "JavaScript moderno" e "JavaScript della vecchia scuola"; Penso che corrispondano rispettivamente all'ECMAScript 6 / ES6 / ECMAScript 2015 e alle versioni precedenti?
Jon Schneider,

1
@JonSchneider: Corretto! Dove dico "JavaScript della vecchia scuola", sto parlando di ECMAScript 5 e dove mi riferisco a "JavaScript moderno", sto prendendo su ECMAScript 6 (aka ECMAScript 2015). Non pensavo fosse davvero così importante entrare nei dettagli qui, però, poiché la maggior parte delle persone vuole solo sapere (1) qual è la differenza tra ambito di blocco e ambito funzionale, (2) quali browser supportano l'ambito di blocco e (3) se è sicuro utilizzare l'ambito del blocco oggi per qualsiasi progetto su cui stanno lavorando. Quindi ho concentrato la mia risposta sull'affrontare tali problemi.
John Slegers,

1
@JonSchneider: (continua) Tuttavia, ho appena aggiunto un link a un articolo di Smashing Magazine su ES6 / ES2015 per coloro che vogliono saperne di più su quali funzionalità sono state aggiunte a JavaScript negli ultimi due anni ... di chiunque altro potrebbe chiedersi cosa intendo con "JavaScript moderno".
John Slegers,

39

Ecco un esempio:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Ti consigliamo di indagare sulle chiusure e su come utilizzarle per creare membri privati .



26

In "Javascript 1.7" (l'estensione di Mozilla a Javascript) si possono anche dichiarare variabili con ambito di blocco con l' letistruzione :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4

2
Sì, ma è sicuro da usare? Voglio dire, sceglierei realisticamente questa implementazione se il mio codice verrà eseguito in WebKit?
IgorGanapolsky,

10
@Python: No, WebKit non supporta let.
kennytm,

Immagino che l'unico uso valido per questo sarebbe se sapessi che tutti i client userebbero un browser Mozilla come per un sistema interno delle aziende.
GazB,

O se stai programmando usando il framework XUL, il framework dell'interfaccia di Mozilla dove costruisci usando css, xml e javascript.
Gerard ONeill,

1
@GazB anche questa è un'idea orribile! Quindi oggi sai che i tuoi clienti usano Mozilla, quindi esce un nuovo memo che afferma che ora stanno usando qualcos'altro. IE il motivo per cui il nostro sistema di pagamento fa schifo ... Devi usare IE8 e mai IE9 o IE10 o Firefox o Chrome perché non funziona
perfettamente

25

L'idea di scoping in JavaScript quando originariamente progettato da Brendan Eich è nata dal linguaggio di scripting HyperCard HyperTalk .

In questa lingua, i display erano fatti in modo simile a una pila di schede. C'era una carta principale indicata come sfondo. Era trasparente e può essere visto come la carta in fondo. Qualsiasi contenuto su questa scheda base è stato condiviso con le carte posizionate sopra di essa. Ogni carta posta in cima aveva il suo contenuto che aveva la precedenza sulla carta precedente, ma se lo desiderava aveva comunque accesso alle carte precedenti.

Questo è esattamente il modo in cui è progettato il sistema di scoping JavaScript. Ha solo nomi diversi. Le carte in JavaScript sono note come Execution Contexts ECMA . Ognuno di questi contesti contiene tre parti principali. Un ambiente variabile, un ambiente lessicale e questo legame. Tornando al riferimento delle carte, l'ambiente lessicale contiene tutto il contenuto delle carte precedenti più in basso nella pila. Il contesto corrente è in cima allo stack e qualsiasi contenuto dichiarato verrà archiviato nell'ambiente variabile. L'ambiente variabile avrà la precedenza in caso di collisioni di denominazione.

Questo legame punterà all'oggetto contenitore. A volte gli ambiti o i contesti di esecuzione cambiano senza che l'oggetto contenitore cambi, come ad esempio in una funzione dichiarata in cui l'oggetto contenitore può essere windowo una funzione di costruzione.

Questi contesti di esecuzione vengono creati ogni volta che viene trasferito il controllo. Il controllo viene trasferito quando inizia l'esecuzione del codice e ciò viene principalmente eseguito dall'esecuzione della funzione.

Questa è la spiegazione tecnica. In pratica, è importante ricordarlo in JavaScript

  • Gli ambiti sono tecnicamente "contesti di esecuzione"
  • I contesti formano una pila di ambienti in cui sono memorizzate le variabili
  • La parte superiore dello stack ha la precedenza (la parte inferiore è il contesto globale)
  • Ogni funzione crea un contesto di esecuzione (ma non sempre un nuovo questo legame)

Applicando questo a uno degli esempi precedenti (5. "Chiusura") in questa pagina, è possibile seguire la pila di contesti di esecuzione. In questo esempio ci sono tre contesti nello stack. Sono definiti dal contesto esterno, dal contesto nella funzione immediatamente invocata chiamato da var six e dal contesto nella funzione restituita all'interno della funzione immediatamente invocata da var six.

i ) Il contesto esterno. Ha un ambiente variabile di a = 1
ii ) Il contesto IIFE, ha un ambiente lessicale di a = 1, ma un ambiente variabile di a = 6 che ha la precedenza nello stack
iii ) Il contesto della funzione restituita, ha un lessico ambiente di a = 6 e questo è il valore a cui fa riferimento l'avviso quando viene chiamato.

inserisci qui la descrizione dell'immagine


17

1) Esiste un ambito globale, un ambito di funzione e gli ambiti with e catch. Non esiste un ambito di livello "blocco" in generale per le variabili: le istruzioni with e catch aggiungono nomi ai loro blocchi.

2) Gli ambiti sono nidificati dalle funzioni fino all'ambito globale.

3) Le proprietà vengono risolte passando attraverso la catena del prototipo. L'istruzione with porta i nomi delle proprietà dell'oggetto nell'ambito lessicale definito dal blocco with.

EDIT: ECMAAScript 6 (Harmony) è stato progettato per supportare let, e so che chrome consente una bandiera 'armonia', quindi forse lo supporta ..

Let sarebbe un supporto per l'ambito scoping a livello di blocco, ma è necessario utilizzare la parola chiave per realizzarlo.

EDIT: Basandomi sul fatto che Benjamin ha sottolineato le dichiarazioni with e catch nei commenti, ho modificato il post e ne ho aggiunto altri. Sia le istruzioni with che catch introducono variabili nei rispettivi blocchi, e questo è un ambito di blocco. Queste variabili sono aliasate alle proprietà degli oggetti passati in esse.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

EDIT: esempio di chiarimento:

test1 è limitato al blocco with, ma è alias a a.test1. 'Var test1' crea una nuova variabile test1 nel contesto lessicale superiore (funzione o globale), a meno che non sia una proprietà di un - quale è.

Yikes! Fai attenzione usando 'with' - proprio come var è un noop se la variabile è già definita nella funzione, è anche un noop rispetto ai nomi importati dall'oggetto! Un piccolo avvertimento sul nome già definito renderebbe questo molto più sicuro. Personalmente non userò mai con questo per questo.


Hai degli errori qui, perché JavaScript ha forme di scoping a blocchi.
Benjamin Gruenbaum,

Le mie orecchie (occhi) sono aperte, Benjamin - Le mie affermazioni sopra sono come ho trattato lo scoping Javascript, ma non si basano sulla lettura delle specifiche. E spero che non ti riferisca all'istruzione with (che è una forma di scoping dell'oggetto) o alla speciale sintassi "let" di Mozilla.
Gerard ONeill,

Bene, l' withaffermazione è una forma di scoping a blocchi, ma le catchclausole sono una forma molto più comune (Curiosità, la v8 implementa catchcon a with) - questa è praticamente l'unica forma di scoping a blocchi nello stesso JavaScript (vale a dire, funzione, globale, try / catch , con e loro derivati), tuttavia gli ambienti host hanno nozioni diverse di scoping, ad esempio eventi incorporati nel browser e il modulo vm di NodeJS.
Benjamin Gruenbaum,

Benjamin: da quello che posso vedere, sia con che con catch, introduco l'oggetto nell'ambito corrente (e quindi le proprietà), ma dopo che il rispettivo blocco termina, le variabili vengono ripristinate. Ad esempio, una nuova variabile introdotta in un catch avrà l'ambito della funzione / metodo che la racchiude.
Gerard ONeill,

2
Questo è esattamente ciò che significa blocco scoping :)
Benjamin Gruenbaum,

9

Ho scoperto che molte persone che non conoscono JavaScript hanno difficoltà a comprendere che l'ereditarietà è disponibile per impostazione predefinita nella lingua e che finora l'ambito delle funzioni è l'unico ambito. Ho fornito un'estensione a un estetista che ho scritto alla fine dello scorso anno chiamato JSPretty. I colori funzione funzionano nell'ambito del codice e associano sempre un colore a tutte le variabili dichiarate in tale ambito. La chiusura viene dimostrata visivamente quando una variabile con un colore di un ambito viene utilizzata in un ambito diverso.

Prova la funzione su:

Guarda una demo su:

Visualizza il codice su:

Attualmente la funzione offre supporto per una profondità di 16 funzioni nidificate, ma attualmente non colora le variabili globali.


1
Non funziona per me con Firefox 26. Incollo il codice o carico un file, faccio clic su Esegui e non succede nulla.
mplwork,

La portata e l'eredità sono due cose diverse.
Ben Aston,

9

JavaScript ha solo due tipi di ambito:

  1. Ambito globale : globale non è altro che un ambito a livello di finestra. Qui, variabile presente in tutta l'applicazione.
  2. Ambito funzionale : la variabile dichiarata all'interno di una funzione con varparola chiave ha un ambito funzionale.

Ogni volta che viene chiamata una funzione, viene creato un oggetto con ambito variabile (e incluso nella catena dell'ambito) seguito da variabili in JavaScript.

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

Scope chain ->

  1. Livello della finestra - ae la outerfunzione è al massimo livello nella catena dell'ambito.
  2. quando la funzione esterna ha chiamato un nuovo variable scope object(e incluso nella catena dell'ambito) aggiunto con una variabile bal suo interno.

Ora, quando una variabile lo arichiede, cerca prima l'ambito variabile più vicino e se la variabile non è presente, allora si sposta sull'oggetto successivo della catena dell'ambito variabile, che in questo caso è a livello di finestra.


1
Non sono sicuro del perché questa non sia la risposta accettata. In realtà esiste solo un ambito funzionale (prima dell'ECMA6 non esisteva un "ambito locale") e collegamenti globali
texasbruce,

9

Solo per aggiungere alle altre risposte, l'ambito è un elenco di ricerca di tutti gli identificatori dichiarati (variabili) e impone un rigido set di regole su come questi sono accessibili al codice attualmente in esecuzione. Questa ricerca può essere ai fini dell'assegnazione alla variabile, che è un riferimento LHS (lato sinistro), oppure può essere allo scopo di recuperare il suo valore, che è un riferimento RHS (lato destro). Queste ricerche sono ciò che il motore JavaScript sta facendo internamente durante la compilazione e l'esecuzione del codice.

Quindi, da questo punto di vista, penso che una foto sarebbe di aiuto che ho trovato nell'ebook Scopes and Closures di Kyle Simpson:

Immagine

Citando dal suo ebook:

L'edificio rappresenta il set di regole dell'ambito nidificato del nostro programma. Il primo piano dell'edificio rappresenta l'ambito attualmente in esecuzione, ovunque tu sia. Il livello più alto dell'edificio è l'ambito globale. Risolvi i riferimenti LHS e RHS osservando il tuo piano attuale e, se non lo trovi, prendi l'ascensore per il piano successivo, guarda lì, poi il successivo e così via. Una volta arrivato all'ultimo piano (l'ambito globale), o trovi quello che stai cercando o no. Ma devi fermarti a prescindere.

Una cosa degna di nota è che "la ricerca dell'ambito si interrompe una volta trovata la prima corrispondenza".

Questa idea di "livelli di ambito" spiega perché "questo" può essere modificato con un ambito appena creato, se viene cercato in una funzione nidificata. Ecco un link che contiene tutti questi dettagli, tutto quello che volevi sapere sull'ambito javascript


8

esegui il codice. spero che questo possa dare un'idea di scoping

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);

8

Ambito globale:

Le variabili globali sono esattamente come le stelle globali (Jackie Chan, Nelson Mandela). Puoi accedervi (ottenere o impostare il valore), da qualsiasi parte della tua applicazione. Le funzioni globali sono come eventi globali (Capodanno, Natale). È possibile eseguirli (chiamare) da qualsiasi parte dell'applicazione.

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

Ambito locale:

Se sei negli Stati Uniti, potresti conoscere Kim Kardashian, famigerata celebrità (in qualche modo riesce a fare i tabloid). Ma le persone al di fuori degli Stati Uniti non la riconosceranno. È una stella locale, legata al suo territorio.

Le variabili locali sono come stelle locali. È possibile accedervi (ottenere o impostare il valore) solo all'interno dell'ambito. Una funzione locale è come gli eventi locali: è possibile eseguire solo (celebrare) all'interno di tale ambito. Se si desidera accedervi dall'esterno dell'ambito, verrà visualizzato un errore di riferimento

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

Consulta questo articolo per una comprensione approfondita dell'ambito


6

Esistono QUASI solo due tipi di ambiti JavaScript:

  • l'ambito di ciascuna dichiarazione var è associato alla funzione che racchiude immediatamente
  • se non esiste alcuna funzione di accodamento per una dichiarazione var, si tratta di ambito globale

Pertanto, qualsiasi blocco diverso dalle funzioni non crea un nuovo ambito. Ciò spiega perché i for-loop sovrascrivono le variabili con ambito esterno:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Utilizzando invece le funzioni:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

Nel primo esempio, non vi era alcun ambito di blocco, quindi le variabili inizialmente dichiarate venivano sovrascritte. Nel secondo esempio, c'era un nuovo ambito dovuto alla funzione, quindi le variabili inizialmente dichiarate erano SHADOWED e non sovrascritte.

Questo è quasi tutto ciò che devi sapere in termini di scoping JavaScript, tranne:

Quindi puoi vedere che l'ambito JavaScript è in realtà estremamente semplice, anche se non sempre intuitivo. Alcune cose da tenere presente:

  • le dichiarazioni var sono sollevate all'inizio dell'ambito. Ciò significa che non importa dove si verifichi la dichiarazione var, per il compilatore è come se il var stesso avvenga in alto
  • vengono combinate più dichiarazioni var all'interno dello stesso ambito

Quindi questo codice:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

è equivalente a:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Questo può sembrare contro intuitivo, ma ha senso dal punto di vista di un designer linguistico imperativo.


5

Modern Js, ES6 +, ' const' e ' let'

Dovresti usare l'ambito del blocco per ogni variabile che crei, proprio come la maggior parte delle altre lingue principali. varè obsoleto . Questo rende il tuo codice più sicuro e più gestibile.

constdovrebbe essere usato per il 95% dei casi . Lo rende quindi il riferimento alla variabile non può cambiare. Le proprietà del nodo Matrice, Oggetto e DOM possono cambiare e dovrebbero probabilmente esserlo const.

letdovrebbe essere usato per qualsiasi variabile che si aspetta di essere riassegnata. Questo include all'interno di un ciclo for. Se si cambia valore oltre l'inizializzazione, utilizzare let.

L'ambito del blocco indica che la variabile sarà disponibile solo tra parentesi quadre in cui è dichiarata. Ciò si estende agli ambiti interni, comprese le funzioni anonime create nell'ambito.


3

Prova questo curioso esempio. Nell'esempio seguente se a fosse un inizializzatore numerico a 0, vedresti 0 e poi 1. Tranne a è un oggetto e javascript passerà a f1 un puntatore di un anziché una copia di esso. Il risultato è che ricevi lo stesso avviso entrambe le volte.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());

3

Esistono solo ambiti di funzione in JS. Non bloccare gli ambiti! Puoi vedere anche cosa sta sollevando.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);

(molto tempo dopo la risposta pubblicata) Blocca l'ambito; developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Bob

2

La mia comprensione è che ci sono 3 ambiti: ambito globale, disponibile a livello globale; ambito locale, disponibile per un'intera funzione indipendentemente dai blocchi; e l'ambito del blocco, disponibile solo per il blocco, l'istruzione o l'espressione su cui è stato utilizzato. L'ambito globale e locale sono indicati con la parola chiave "var", all'interno di una funzione o all'esterno, mentre l'ambito del blocco è indicato con la parola chiave "let".

Per coloro che credono che ci sia solo un ambito globale e locale, spiega perché Mozilla avrebbe un'intera pagina che descrive le sfumature dell'ambito del blocco in JS.

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


2

Un problema molto comune non ancora descritto che spesso si verificano nei coder front-end è l'ambito visibile a un gestore di eventi inline nell'HTML, ad esempio con

<button onclick="foo()"></button>

L'ambito delle variabili a cui un on*attributo può fare riferimento deve essere:

  • globale (i gestori inline funzionanti fanno quasi sempre riferimento a variabili globali)
  • una proprietà del documento (ad esempio, querySelectorcome indicherà una variabile autonoma document.querySelector; raro)
  • una proprietà dell'elemento a cui il gestore è associato (come sopra; raro)

Altrimenti, verrà visualizzato un ReferenceError quando viene richiamato il gestore. Quindi, ad esempio, se il gestore inline fa riferimento a una funzione definita all'interno window.onload o $(function() {, il riferimento fallirà, perché il gestore inline può fare riferimento solo a variabili nell'ambito globale e la funzione non è globale:

Proprietà della documente proprietà dell'elemento conduttore è collegato a può anche essere fatto riferimento come variabili indipendenti all'interno movimentatori linea perché movimentatori linea vengono richiamati all'interno di due withblocchi , uno per la document, uno per l'elemento. La catena di portata delle variabili all'interno di questi gestori è estremamente non intuitiva e un gestore di eventi di lavoro richiederà probabilmente una funzione per essere globale (e probabilmente dovrebbe essere evitato l'inquinamento globale non necessario ).

Poiché la catena dell'ambito all'interno dei gestori inline è così strana e poiché i gestori inline richiedono l'inquinamento globale per funzionare, e poiché i gestori inline a volte richiedono una brutta fuga di stringhe quando si passano gli argomenti, è probabilmente più facile evitarli. Invece, collega i gestori di eventi utilizzando Javascript (come con addEventListener), anziché con markup HTML.


Su una nota diversa, a differenza dei normali <script>tag, che vengono eseguiti al livello superiore, il codice all'interno dei moduli ES6 viene eseguito nel proprio ambito privato. Una variabile definita nella parte superiore di un <script>tag normale è globale, quindi puoi fare riferimento ad altri <script>tag, come questo:

Ma il livello superiore di un modulo ES6 non è globale. Una variabile dichiarata nella parte superiore di un modulo ES6 sarà visibile solo all'interno di quel modulo, a meno che la variabile non sia esplicitamente modificata exporto a meno che non sia assegnata a una proprietà dell'oggetto globale.

Il livello superiore di un modulo ES6 è simile a quello dell'interno di un IIFE al livello superiore in un normale <script>. Il modulo può fare riferimento a tutte le variabili che sono globali e nulla può fare riferimento a nulla all'interno del modulo a meno che il modulo non sia esplicitamente progettato per esso.


1

In JavaScript ci sono due tipi di ambito:

  • Ambito locale
  • Portata globale

La funzione Below ha una variabile di ambito locale carName. E questa variabile non è accessibile dall'esterno della funzione.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

La classe di seguito ha una variabile di ambito globale carName. E questa variabile è accessibile da qualsiasi parte della classe.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}

1

ES5 e precedenti:

Le variabili in Javascript erano inizialmente (pre ES6) con ambito lessicale funzionale. Il termine con ambito lessicale significa che è possibile visualizzare l'ambito delle variabili "osservando" il codice.

Ogni variabile dichiarata con la varparola chiave è associata alla funzione. Tuttavia, se all'interno di tale funzione vengono dichiarate altre funzioni, tali funzioni avranno accesso alle variabili delle funzioni esterne. Questa si chiama catena di ambito . Funziona nel modo seguente:

  1. Quando una funzione cerca di risolvere un valore variabile, per prima cosa guarda il suo ambito. Questo è il corpo della funzione, ovvero tutto tra parentesi graffe {} (ad eccezione delle variabili all'interno di altre funzioni che rientrano in questo ambito).
  2. Se non riesce a trovare la variabile all'interno del corpo della funzione , salirà sulla catena e guarderà l'ambito della variabile nella funzione in cui è stata definita la funzione . Questo è ciò che si intende con ambito lessicale, possiamo vedere nel codice dove è stata definita questa funzione e quindi determinare la catena dell'ambito semplicemente guardando il codice.

Esempio:

// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

Che cosa succede quando stiamo cercando di accedere alle variabili foo, bare foobaralla console è il seguente:

  1. Proviamo a registrare foo sulla console, foo può essere trovato all'interno della funzione innerFuncstessa. Pertanto, il valore di foo viene risolto nella stringa innerFunc.
  2. Cerchiamo di accedere alla barra della console, non è possibile trovare la barra all'interno della funzione innerFuncstessa. Pertanto, dobbiamo scalare la catena di portata . Innanzitutto esaminiamo la funzione esterna in cui è innerFuncstata definita la funzione . Questa è la funzione outerFunc. Nell'ambito di outerFuncpossiamo trovare la barra delle variabili, che contiene la stringa 'outerFunc'.
  3. foobar non può essere trovato in innerFunc. . Pertanto, dobbiamo scalare la catena dell'oscilloscopio nell'ambito innerFunc. Inoltre non può essere trovato qui, saliamo un altro livello nell'ambito globale (ovvero l'ambito più esterno). Qui troviamo la variabile foobar che contiene la stringa "globale". Se non avesse trovato la variabile dopo aver scalato la catena dell'oscilloscopio, il motore JS lancerebbe un errore di riferimento .

ES6 (ES 2015) e precedenti:

Gli stessi concetti di lessical scope e scopechain si applicano ancora ES6. Tuttavia, sono stati introdotti nuovi modi per dichiarare le variabili. Ci sono i seguenti:

  • let: crea una variabile con ambito di blocco
  • const: crea una variabile con ambito di blocco che deve essere inizializzata e non può essere riassegnata

La più grande differenza tra vare let/ constè che varè nell'ambito della funzione mentre let/ constsono nell'ambito del blocco. Ecco un esempio per illustrare questo:

let letVar = 'global';
var varVar = 'global';

function foo () {
  
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
  
  console.log(letVar);
  console.log(varVar);
}


foo();

Nell'esempio precedente letVar registra il valore globale perché le variabili dichiarate con letsono a ambito di blocco. Smettono di esistere al di fuori del rispettivo blocco, quindi non è possibile accedere alla variabile al di fuori del blocco if.


0

In EcmaScript5 esistono principalmente due ambiti, ambito locale e ambito globale, ma in EcmaScript6 abbiamo principalmente tre ambiti, ambito locale, ambito globale e un nuovo ambito chiamato ambito blocco .

Esempio di ambito di blocco è: -

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}

0

ECMAScript 6 ha introdotto le parole chiave let e const. Queste parole chiave possono essere utilizzate al posto della parola chiave var. Contrariamente alla parola chiave var, le parole chiave let e const supportano la dichiarazione di ambito locale all'interno delle istruzioni di blocco.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10

0

Mi piace molto la risposta accettata ma voglio aggiungere questo:

Scope raccoglie e mantiene un elenco di ricerca di tutti gli identificatori dichiarati (variabili) e applica un rigido set di regole su come questi sono accessibili al codice attualmente in esecuzione.

Scope è un insieme di regole per la ricerca di variabili in base al nome dell'identificatore.

  • Se non è possibile trovare una variabile nell'ambito immediato, Engine consulta il successivo ambito contenitore esterno, continuando fino a quando non viene trovato o fino a quando non viene raggiunto l'ambito più esterno (ovvero globale).
  • È l'insieme di regole che determina dove e come una variabile (identificatore) può essere cercata. Questa ricerca può essere ai fini dell'assegnazione alla variabile, che è un riferimento LHS (lato sinistro), oppure può essere allo scopo di recuperare il suo valore, che è un riferimento RHS (lato destro) .
  • I riferimenti LHS derivano dalle operazioni di assegnazione. Le assegnazioni relative all'ambito possono avvenire con l'operatore = o passando argomenti ai parametri della funzione (assegnazione a).
  • Il motore JavaScript prima compila il codice prima di essere eseguito, e così facendo divide le istruzioni come var a = 2; in due passaggi separati: 1 °. Innanzitutto, var a per dichiararlo in tale ambito. Questo viene eseguito all'inizio, prima dell'esecuzione del codice. 2 °. Successivamente, a = 2 per cercare la variabile (riferimento LHS) e assegnarla se trovata.
  • Entrambe le ricerche di riferimento LHS e RHS iniziano nell'ambito attualmente in esecuzione e, se necessario, (ovvero, non trovano quello che stanno cercando lì), si arrampicano nell'ambito nidificato, un ambito (piano ) alla volta, alla ricerca dell'identificatore, fino a quando non raggiungono il globale (ultimo piano) e si fermano, o lo trovano o no. Riferimenti RHS non completati provocano il lancio di ReferenceError. I riferimenti LHS non completati risultano in un globale automatico, creato in modo implicito con quel nome (se non in modalità Strict) o un errore di riferimento (se in modalità Strict).
  • l'ambito è costituito da una serie di "bolle" che fungono da contenitore o da bucket, in cui vengono dichiarati identificatori (variabili, funzioni). Queste bolle nidificano ordinatamente l'una nell'altra e questa nidificazione è definita al momento dell'autore.

-3

Esistono due tipi di ambiti in JavaScript.

  1. Ambito globale : la variabile annunciata in ambito globale può essere utilizzata in modo uniforme in qualsiasi parte del programma. Per esempio:

    var carName = " BMW";
    
    // code here can use carName
    
    function myFunction() {
         // code here can use carName 
    }
  2. Ambito funzionale o ambito locale : la variabile dichiarata in questo ambito può essere utilizzata solo nella propria funzione. Per esempio:

    // code here can not use carName
    function myFunction() {
       var carName = "BMW";
       // code here can use carName
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.