Scope, hoisting și this
Unde trăiesc variabilele și de ce își „pierde” o metodă this-ul.
Actualizat
Ce este scope
Scope = zona din cod în care o variabilă există și poate fi folosită. În afara ei, variabila nu există.
function order() {
const total = 100 // există doar în order()
}
console.log(total) // ✗ ReferenceErrorDe ce există: fără scope, toate variabilele ar fi globale și s-ar călca pe picioare (două funcții cu un i fiecare).
Tipurile de scope
| Tip | Creat de | Conține |
|---|---|---|
| global | fișierul / pagina | tot ce declari în afara funcțiilor (în module ES — global doar pentru acel modul) |
| funcție | fiecare funcție | parametrii și variabilele din ea (inclusiv var) |
| bloc | orice { }: if, for, while, {} simplu |
let, const, class |
const app = 'learn' // global (al modulului)
function render() {
const title = 'Funcții' // scope de funcție
if (title) {
const upper = title.toUpperCase() // scope de bloc
}
upper // ✗ nu mai există
}Lexical scope și scope chain
Când folosești o variabilă, JS o caută în scope-ul curent, apoi în scope-ul părinte, apoi în părintele lui… până la global. Acest lanț se numește scope chain.
Important: părintele e decis de locul unde e scrisă funcția în cod (lexical), nu de unde e apelată.
const x = 'global'
function outer() {
const x = 'outer'
return function inner() { return x } // inner e scrisă în outer → vede x-ul lui outer
}
outer()() // 'outer'De aici vine closure — vezi Funcții.
Ce este hoisting
Hoisting („ridicare”) = înainte să ruleze codul, JS parcurge scope-ul și înregistrează toate declarațiile. Efectul: unele lucruri pot fi folosite înainte de linia unde sunt scrise.
Fiecare tip de declarație e ridicat diferit:
| Declarație | Ridicată? | Ce găsești dacă o folosești înainte de linia ei |
|---|---|---|
function f() {} |
da, cu tot cu corp | funcția merge normal |
var x = 1 |
da, dar fără valoare | undefined |
let / const |
da, dar blocată | ReferenceError (TDZ) |
class A {} |
da, dar blocată | ReferenceError |
const f = () => {} |
ca orice const |
ReferenceError |
sayHi() // ✓ 'Salut' — declarația de funcție e ridicată complet
function sayHi() { return 'Salut' }
console.log(a) // undefined — var e ridicat, valoarea vine abia la linia lui
var a = 1
console.log(b) // ✗ ReferenceError
const b = 2TDZ — temporal dead zone
Între începutul scope-ului și linia unde e declarat un let/const, variabila e într-o „zonă moartă” (TDZ): JS știe că există, dar refuză să te lase s-o folosești. E un lucru bun — prinde bug-uri pe care var le ascundea cu undefined.
Ce înseamnă practic: poți organiza un fișier cu funcția principală sus și helper-ele (declarații function) jos — merge datorită hoisting-ului.
Ce este this
this e o variabilă specială, disponibilă în funcții, care indică obiectul în contextul căruia rulează funcția. Spre deosebire de restul variabilelor, valoarea lui this nu depinde de unde e scrisă funcția, ci de cum e apelată.
Regulile, în ordinea priorității
| Cum apelezi | this este |
Exemplu |
|---|---|---|
new Fn() |
obiectul nou creat | new User('Ana') |
fn.call(obj), fn.apply(obj), fn.bind(obj) |
obj, setat explicit |
greet.call(user) |
obj.method() |
obiectul din fața punctului | user.greet() |
fn() simplu |
undefined (în module / strict mode) |
const g = user.greet; g() |
| arrow function | this-ul din locul unde a fost scrisă — nu are propriul this |
() => this.name |
const user = {
name: 'Ana',
greet() { return `Salut, ${this.name}` },
}
user.greet() // 'Salut, Ana' — this = user
const greet = user.greet
greet() // ✗ this e undefined — metoda a fost „desprinsă” de obiect
const bound = user.greet.bind(user)
bound() // ✓ 'Salut, Ana'De ce arrow functions „repară” callback-urile
const timer = {
seconds: 0,
start() {
setInterval(function () { this.seconds++ }, 1000) // ✗ this nu e timer
setInterval(() => { this.seconds++ }, 1000) // ✓ arrow ia this din start()
},
}Când îți pasă de this în practică
- În React modern (funcții + hooks) aproape niciodată.
- În clase (erori custom, SDK-uri), în event listeners clasici și în cod mai vechi.
- Regula: metode → funcții normale; callback-uri în interiorul lor → arrow; pasezi o metodă ca callback →
bindsau() => obj.method().
Pe scurt
- Scope = unde trăiește o variabilă: global, funcție, bloc. Căutarea urcă pe scope chain, după locul unde e scris codul.
- Hoisting = declarațiile sunt înregistrate înainte de rulare; funcțiile merg înainte de definire,
let/constdau eroare (TDZ). thisdepinde de cum apelezi funcția; arrow functions nu au propriulthis.