Domeniul de vizibilitate al variabilelor
Toate variabilele și constantele în JavaScript au o anumită arie de vizibilitate în cadrul căreia pot acționa.
Variabilele globale
Toate variabilele și constantele care sunt declarate în afara funcțiilor sunt considerate globale:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
</head>
<body>
<script>
var a = 5;
let b = 8;
const c = 9;
function displaySum(){
var d = a + b + c;
console.log(d);
}
displaySum(); // 22
</script>
</body>
</html>
Aici variabilele a și b, precum și constanta c, sunt globale. Ele sunt accesibile din orice parte a programului.
Însă variabila d nu este globală, deoarece este definită în interiorul unei funcții și este vizibilă doar în acea funcție.
Definirea domeniului local de vizibilitate
Pentru a defini un domeniu local de vizibilitate în JavaScript, se utilizează acoladele { }, care creează un bloc de cod. Acest bloc de cod poate fi anonim sau poate fi numit, de exemplu, o funcție, sau poate reprezenta o construcție condițională sau ciclică. De exemplu, definirea variabilelor într-un bloc de cod fără nume:
{
var a = 5;
let b = 8;
const c = 9;
}
Cu toate acestea, în acest caz, comportamentul variabilei depinde de modul în care este definită (prin intermediul var sau let) și de tipul blocului. var definește variabile locale la nivelul funcției, în timp ce let definește variabile locale la nivelul blocului de cod (similar, const definește constante la nivelul blocului de cod). Să examinăm care este diferența.
Variabile și constantele funcției
Variabilele și constantele definite în interiorul unei funcții sunt vizibile (adică pot fi utilizate) doar în cadrul acelei funcții:
function print(){
var a = 5;
let b = 8;
const c = 9;
console.log("Function print: a =", a);
console.log("Function print: b =", b);
console.log("Function print: c =", c);
}
print();
console.log("Global: a =", a); // Uncaught ReferenceError: a is not defined
Variabilele a și b, precum și constanta c, sunt locale; ele există doar în cadrul funcției. În afara funcției, nu pot fi utilizate, așa că vom obține următorul rezultat în consolă:
Function print: a= 5 Function print: b= 8 Function print: c= 9 Uncaught ReferenceError: a is not defined
Aici observăm că la încercarea de a accesa variabila a în afara funcției print(), browser-ul afișează o eroare. Această comportare nu depinde de tipul variabilei - fie că este var sau let, sau o constantă. Asemenea comportament este similar pentru toate variabilele și constantele.
Variabile locale în blocurile de cod, condiții și bucle
Cu variabilele definite în blocuri de cod fără nume, precum și în bucle și construcții condiționale, situația este puțin mai complicată.
Variabila var
Variabila declarată cu ajutorul var poate fi utilizată în afara blocului de cod:
// Bloc fără nume
{
var a = 5;
}
console.log("a =", a); // a = 5
// Construcție condițională
if (true) {
var b = 6;
}
console.log("b =", b); // b = 6
// Buclă
for (let i = 0; i < 5; i++) {
var c = 7;
}
console.log("c =", c); // c = 7
Unica condiție pentru a inițializa variabila este ca blocul de cod să fie executat. Astfel, în exemplul de mai sus, condițiile în construcția if și în bucla for sunt setate astfel încât blocurile acestor construcții să fie executate. Cu toate acestea, dacă condiția nu este îndeplinită și blocul nu este executat, variabila nu va fi inițializată în afara blocului respectiv. În cazul variabilei c, de exemplu, dacă bucla for nu se execută, atunci încercarea de a accesa c în afara buclei va genera o eroare.
if(false){
var b = 6;
}
console.log("b =", b); // b = undefined
// bucla
for(let i = 1; i < 0; i++){
var c = 7;
}
console.log("c =", c); // c = undefined
În acest caz, putem totuși să facem referire la variabile, dar ele vor avea valoarea undefined.
Variabila let și constantele
Acum să vedem cum se comportă într-o situație similară variabilele definite cu ajutorul let:
{
let a = 5;
}
console.log("a =", a); // Uncaught ReferenceError: a is not defined
În acest caz, vom obține o eroare. Putem utiliza variabilele let definite în interiorul unui bloc de cod doar în cadrul acelui bloc de cod.
Același lucru se aplică și pentru constante:
{
const b = 5;
}
console.log("b =", b); // Uncaught ReferenceError: b is not defined
Ascunderea variabilelor
Ce se întâmplă dacă avem două variabile - una globală și cealaltă locală, care au același nume:
var z = 89;
function print(){
var z = 10;
console.log(z); // 10
}
print(); // 10
În acest caz, în funcție se va utiliza variabila z care este definită direct în funcție. Cu alte cuvinte, variabila locală va ascunde variabila globală. Cu toate acestea, comportamentul specific al ascunderii depinde de modul în care este definită variabila.
Ascunderea variabilei var
Mai sus a fost menționat că var definește variabila la nivelul funcției. Prin urmare, cu ajutorul operatorului var, NU putem defini simultan două variabile cu același nume într-o funcție și într-un bloc de cod în acea funcție. Dacă o facem, la declararea variabilei la nivelul blocului, schimbăm valoarea variabilei la nivelul funcției:
function displayZ(){
var z = 20;
{
var z = 30; // Nu definește o variabilă nouă, ci schimbă valoarea variabilei z la nivelul funcției
console.log("Block:", z);
}
console.log("Function:", z);
}
displayZ();
Aici, definirea variabilei z în interiorul blocului de fapt va echivala cu modificarea valorii variabilei la nivelul funcției și, practic, aceasta va fi aceeași variabilă. Afișajul în consolă:
Block: 30 Function: 30
Ascunderea variabilei let
După cum s-a menționat mai sus, operatorul let definește variabile la nivelul blocului de cod. Cu alte cuvinte, fiecare bloc de cod definește o nouă zonă de vizibilitate în care există variabila. În afara blocului de cod în care este definită variabila, aceasta nu există. Prin urmare, putem defini simultan o variabilă la nivelul blocului de cod și la nivelul funcției (spre deosebire de var):
let z = 10;
function displayZ(){
let z = 20;
{
let z = 30;
console.log("Block:", z);
}
console.log("Function:", z);
}
displayZ();
console.log("Global:", z);
În acest caz, în cadrul funcției displayZ este definit un bloc de cod în care este declarată variabila z. Acest bloc ascunde variabila globală și variabila z definită la nivelul funcției.
Și în acest context, vom obține următorul rezultat în consolă.
Block: 30 Function: 20 Global: 10
Constante
Tot ce a fost menționat despre operatorul let se aplică și operatorului const, care definește constante la nivelul blocului de cod. Blocurile de cod stabilesc domeniul de vizibilitate pentru constante, iar constantele definite în blocuri imbricate ascund constantele exterioare cu același nume:
const z = 10;
function displayZ(){
const z = 20;
{
const z = 30;
console.log("Block:", z); // 30
}
console.log("Function:", z); // 20
}
displayZ();
console.log("Global:", z); // 10
Lanțul de vizibilitate
Când rulează codul, atunci când interpretorul se confruntă cu un anumit identificator (numele variabilei, constantei, funcției), el caută mai întâi definiția acestui identificator în domeniul de vizibilitate curent. Acesta este modul în care funcționează ascunderea variabilelor și constantelor. De exemplu:
const z = 10;
function displayZ(){
const z = 20;
console.log(z); // 20
}
displayZ(); // 20
Aici interpretorul va observa că în funcția displayZ există o referire la identificatorul z și va căuta definiția acestui identificator în interiorul funcției displayZ. Și deoarece în această funcție există o definiție pentru constanta const z = 20, această constantă va fi utilizată.
Alt exemplu:
const z = 10;
function displayZ(){
console.log(z); // 10
}
displayZ(); // 10
Acum, în interiorul funcției displayZ, nu există o definiție pentru identificatorul z, astfel că pentru a-l găsi, se aplică lanțul de vizibilitate - interpretorul se adresează domeniului său de vizibilitate înconjurător și efectuează căutarea acolo. Mai precis, se urmăresc domeniile de vizibilitate în lanț, începând de la cel actual și mergând către cele exterioare, până la domeniul de vizibilitate global.
Variabilele nedeclarate
La definirea variabilelor în JavaScript, putem să nu folosim cuvântul cheie let sau var. De exemplu:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
</head>
<body>
<script>
{
username = "Tom";
}
console.log(username); // nu există erori
{
console.log(username); // nu există erori, accesibil în interiorul altor blocuri de cod
}
</script>
</body>
</html>
Dacă nu folosim cuvintele cheie let/var la definirea unei variabile într-o funcție, atunci acea variabilă va deveni globală. De exemplu:
function setAge(){
userage = 39;
}
setAge();
console.log(userage); // 39
La nivelul funcției setAge, variabila userage este accesibilă în afara funcției în contextul global. Singura condiție este să apelăm funcția unde este definită această variabilă.
Cu toate acestea, dacă nu apelăm funcția, variabila nu va fi definită:
function setAge(){
userage = 39;
}
// setAge(); Funcția NU este apelată
console.log(userage); // eroare - Uncaught ReferenceError: userage is not defined
Am obține aceeași eroare dacă nu numai că am atribui o valoare variabilei, ci și dacă am defini-o ca locală față de funcție:
function setAge(){
var userage = 39;
}
setAge();
console.log(userage); // eroare - Uncaught ReferenceError: userage is not defined
strict mode
Definirea de variabile globale în funcții poate duce la potențiale erori. Pentru a le evita, se utilizează strict mode sau modul strict. Strict mode poate fi activat în două moduri:
- Adăugați expresia "use strict" la începutul codului JavaScript, astfel încât strict mode să fie aplicat întregului cod.
- Adăugați expresia "use strict" la începutul corpului funcției, astfel încât strict mode să fie aplicat doar acelei funcții.
Aplicarea strict mode la nivel global:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
</head>
<body>
<script>
"use strict"; // folosim strict mode
username = "Tom"; // Uncaught ReferenceError: username is not defined
console.log(username);
</script>
</body>
</html>
În acest caz, vom primi o eroare SyntaxError: Unexpected identifier, care indică faptul că variabila username nu este definită.
O eroare similară o vom obține la definirea unei variabile globale într-o funcție:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
</head>
<body>
<script>
"use strict"; // folosim strict mode
function setAge(){
userage = 39; // Uncaught ReferenceError: userage is not defined
}
setAge();
console.log(userage);
</script>
</body>
</html>
Exemplu de utilizare a modului strict la nivelul unei funcții:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
</head>
<body>
<script>
username = "Tom"; // normal
console.log(username); // Tom
function setAge(){
"use strict"; // se utilizează modul strict la nivelul funcției
userage = 39; // Uncaught ReferenceError: userage is not defined
}
setAge();
console.log(userage);
</script>
</body>
</html>