JavaScript Hoisting Nedir?
JavaScript hoisting kavramı net açıklamayla: değişkenler nasıl yukarı çekilir, var-let-const farkı, fonksiyon deklarasyonu vs ifadesi, temporal dead zone ve mulakat tuzakları.
Closetrafi bosalt, once yanlis inanclar
Hoisting (türkce: kaldirma, yükseltme), JavaScript'in en cok korkulan ve en cok yanlis anlatilan kavramlarindan biri. Aslinda kavram basit — ama JavaScript'in "kod calistir" sekli C'den, Java'dan farkli oldugu icin isler karisiyor.
Bu yazi boyunca 3 seyi anlatacagim: (1) Hoisting gercekte ne, (2) var/let/const farki, (3) Mulakatta nasil cevaplanir. 11 dakikada bitmis olacaksin.
Benzetme: İskele kurmak
Bir bina insa ediyorsun. Önce iskele kurarsin — temel atmadan önce bile iskele hazir olur. Sonra temeli atarsin, kolonlari dikersin, duvarlari örersin. Iskele = hoisting. JavaScript motoru, kodu calistirmaya baslamadan önce "iskele"yi kurar: degisken ve fonksiyonlari kapsam (scope) icinde kayit eder. Sonra sirayla atama yapar, calistirir.
Onemli: Iskele yer acar ama icine henüz sey koymaz. Yani var a yazdiginda motor a icin "iskele" kurar, ama a = 5 yazana kadar a'nin degeri undefined'dir. let a yazdiginda da iskele kurulur ama icerisi kapiyla kapatilir — sen atama yapana kadar kimse giremez (TDZ).
var, let, const farkı
Asagidaki kodu calistirmadan once ne olacagini tahmin et:
// SENARYO 1: var
console.log("var:", x); // ?
var x = 5;
console.log("var sonra:", x); // ?Cikti: undefined ve 5. Motor, var x'i kapsam basina alir ama degeri undefined'dir. Atama satirina gelince x = 5 olur.
// SENARYO 2: let
console.log("let:", y); // ?
let y = 10;
console.log("let sonra:", y); // ?Cikti: ReferenceError: Cannot access 'y' before initialization. Motor let y'yi kapsam basina alir ama TDZ (Temporal Dead Zone) icinde oldugu icin erisilemez. Atama satirina gelince TDZ biter.
// SENARYO 3: const
console.log("const:", z); // ?
const z = 15; // atama zorunlu!
console.log("const sonra:", z); // ?Cikti: ReferenceError (TDZ), sonra 15. const icin atama zorunlu — sadece const z; yazarsan yine ReferenceError alirsin.
| Anahtar kelime | Yükseltilir mi? | Atama öncesi erişim |
|---|---|---|
| var | Evet, undefined | undefined döner |
| let | Evet, ama TDZ | ReferenceError |
| const | Evet, ama TDZ + atama zorunlu | ReferenceError |
Fonksiyon deklarasyonu vs ifadesi
Mulakatlarda en cok sorulan 2. konu: function declaration ve function expression nasil farkli yükseltilir?
// Function declaration — TAM yükseltilir (deklarasyon + gövde)
console.log(selamla("Ali")); // "Selam Ali" ✓
function selamla(isim) {
return "Selam " + isim;
}
// Function expression — sadece const ismi yükseltilir, deger atanmaz
console.log(hosgeldin("Ayşe")); // ReferenceError ❌
const hosgeldin = function(isim) {
return "Hoş geldin " + isim;
};Function declaration (function foo() ) — hem deklarasyon hem gövde scope'un en üstüne çekilir. Cagirildiginda hazir.
Function expression (const foo = function() ) — sadece const değişken ismi yükseltilir (TDZ'de), deger atanmaz. Cagirildiginda henüz undefined, ReferenceError.
"Yukaridaki kodda selamla calisir ama hosgeldin calismaz, neden?" Cevap: function declaration tamamen yükseltilir, function expression sadece const ismini yükseltir (TDZ'de kalir). Bu kucuk fark, JavaScript mülakatlarinda 3-4 farkli soruyu dogurur.
Temporal Dead Zone (TDZ)
TDZ, "zamansal ölü bölge" demek. let ve const değişkenleri deklarasyondan atamaya kadar olan sürede erişilemez.
function tdziGoster() {
console.log(basla()); // ReferenceError ❌ (TDZ)
const selamla = function() {
return "Merhaba";
};
function basla() {
return "Başla!";
}
}
tdziGoster();Burada selamla bir const function expression. basla ise function declaration. console.log(basla()) satırında selamla henüz atanmamis (TDZ) ama basla yükseltilmis. Ancak hata alirsin cünkü JS satir sirayla calisir, "TDZ'deki selamla" hatasi daha once firlatilir.
ES6 (2015) öncesi sadece var vardi. var'in undefined davranisi kafa karistiriciydi. ES6 ile gelen let ve const "block scope" kavramini ve TDZ'yi ekledi — boylece hata yapmak yerine aninda uyari aliyorsun.
Mulakat tuzakları
Asagidaki 3 örnek, mulakatta en cok sorulan ve en cok yanlis cevaplanan tuzaklardir.
Tuzak 1: Sira karisik console.log'lar
var a = 1;
let b = 2;
const c = 3;
{
console.log(a, b, c); // ?
var a = 10;
let b = 20;
const c = 30;
}
console.log(a, b, c); // ?Ilk console.log: ReferenceError (TDZ). b ve c yeni scope'ta TDZ'de. a var ama yeni scope'ta da var, undefined (var her yere yükselir). Ikinci console.log: 10, 2, 3. Dış a degisti (10), b ve c kendi scope'larinda degisti.
Tuzak 2: Function expression icinde fonksiyon cagir
var x = 1;
function test() {
console.log(x);
var x = 2;
console.log(x);
}
test();Cikti: undefined ve 2. test icinde var x scope'un en üstüne yükseltilir ve undefined olur. Ilk console.log(x) bu local x'i yazdirir, sonra atama yapilir.
Tuzak 3: typeof ile TDZ
console.log(typeof degisken); // ?
let degisken = "selam";Cikti: ReferenceError. typeof bile TDZ'deki degiskene erisemez. typeof undefinedDegisken yazsaydin "undefined" donerdi — ama let/const ile tanimli degisken icin TDZ aktif, ReferenceError.
Mulakat SSS
JavaScript hoisting nedir, en basit şekilde nasıl açıklanır?
Hoisting, JavaScript motorunun kodu çalıştırmadan önce değişken ve fonksiyon deklarasyonlarını kapsamın en üstüne 'çekmesi' işlemidir. Bu fiziksel bir taşıma değil, motorun derleme aşamasında yaptığı bir hazırlıktır. var, function declaration ve class declaration farklı şekilde yükseltilir; let ve const ise yükseltilir ama kullanılamaz (temporal dead zone).
var, let ve const hoisting açısından nasıl farklı?
var: Hem deklarasyon hem atama undefined olarak yükseltilir. Kullanmadan önce değer undefined olur. let ve const: Sadece deklarasyon yükseltilir (TDZ — Temporal Dead Zone), değer atanmaz. Kullanmaya çalışırsan ReferenceError alırsın. const için ayrıca atama zorunluluğu vardır.
Function declaration ve function expression hoisting farkı nedir?
Function declaration (function foo() {}) tam olarak yükseltilir — hem deklarasyon hem gövde scope'un en üstüne çıkar. Function expression (const foo = function() {}) ise sadece const davranışı gösterir: değişken yükseltilir ama değer atanmaz, TDZ'dedir. Kullanmadan önce tanımlanmalıdır.
Temporal dead zone (TDZ) ne demek?
TDZ, let ve const değişkenlerinin hoisting sonrasında değer atanana kadar geçtiği 'erişilemez bölge'dir. Değişken scope'un en üstüne çekilir ama atanmamış olduğu için erişmeye çalışmak ReferenceError fırlatır. Atama yapıldığı an TDZ biter, değişken kullanılabilir hale gelir.
Hoisting performansı etkiler mi?
Hayır, performans üzerinde ölçülebilir bir etkisi yoktur. Hoisting sadece derleme (parse) aşamasında bir kez yapılan bir işlemdir, çalışma zamanında ekstra maliyet getirmez. Ancak hoisting nedeniyle oluşan kod karmaşıklığı, bakım maliyetini artırabilir — bu yüzden modern kodda let/const tercih edilir.
Mulakat sorusu: console.log(a); var a = 5; ne yazdırır?
Çıktı: 'undefined'. Çünkü var a deklarasyonu kapsamın en üstüne çekilir (a = undefined), sonra console.log çalışır, sonra a = 5 atanır. let ve const ile yazsaydın, console.log sırasında 'ReferenceError: Cannot access 'a' before initialization' hatası alırdın (TDZ).
Bir cümlede özet
Hoisting, JavaScript'in "kod çalışmadan önce deklarasyonları kapsamın tepesine koyması" işlemidir. var için bu yumuşaktır (undefined döner), let/const için serttir (TDZ, ReferenceError).
Modern JavaScript'te her zaman let veya const kullan, var'dan kaçın. Bu hem hataları erken yakalar hem de kodu okunabilir yapar.
Sıradaki adımlar
- JavaScript Closure yazımızla ilgili kavramı pekiştir
- Sıfırdan Zirveye ile programlama temellerini öğren
- Mülakat soruları ile hoisting gerektiren problemleri çöz
İlgili Yazılar
Hoisting öğrendin, diğerleri de sırada
JavaScript'in en çok sorulan mülakat konularını sırayla öğren: closure, this, prototype, async/await, event loop.