Bir önceki bölümde değişken türlerinin görünürlük alanlarını karşılaştırmıştık. Şimdi bir adım geriye çekilip motorun kodunuzu hangi sırayla ele aldığına bakalım. JavaScript bir fonksiyonu çalıştırmadan önce onu okur, iç…
Bir önceki bölümde değişken türlerinin görünürlük alanlarını karşılaştırmıştık. Şimdi bir adım geriye çekilip motorun kodunuzu hangi sırayla ele aldığına bakalım. JavaScript bir fonksiyonu çalıştırmadan önce onu okur, içindeki tanımları not eder ve ancak ondan sonra satırları yürütür. Bu iki aşamalı davranışa hoisting (kaldırma) denir.
Kapsam zinciri
Her fonksiyon çağrısı kendi kapsamını yaratır. Bir isim arandığında motor önce içinde bulunduğu kapsama, bulamazsa bir üsttekine, oradan da bulamazsa küresel kapsama bakar. Bu ardışık aramaya kapsam zinciri denir ve tek yönlüdür: iç kapsam dışarıyı görür, dış kapsam içeriyi göremez.
const uygulamaAdi = "Defter";
function disKapsam() {
const kullanici = "Ayşe";
function icKapsam() {
console.log(uygulamaAdi, kullanici); // Defter Ayşe
}
icKapsam();
}
disKapsam();
console.log(kullanici); // ReferenceError
Bu kural, bir fonksiyonun tanımlandığı yerdeki değişkenleri sonradan da hatırlamasını sağlar; kapanış (closure) dediğimiz davranışın temeli budur.
Ne kaldırılır, ne kaldırılmaz?
Kaldırma her tanım türü için aynı işlemez:
- Fonksiyon bildirimleri gövdeleriyle birlikte kaldırılır; tanımdan önce çağırabilirsiniz.
var değişkenleri yalnızca isim olarak kaldırılır, değeri atanmaz; erken okursanız undefined alırsınız.
let ve const de kaldırılır ama başlatılmaz; tanım satırına kadar geçici ölü bölgededirler ve okumaya çalışmak hata fırlatır.
selamla(); // "Merhaba" — çalışır
console.log(sayac); // undefined
console.log(toplam); // ReferenceError
function selamla() { console.log("Merhaba"); }
var sayac = 0;
let toplam = 0;
Fonksiyon ifadeleri farklıdır
Bir fonksiyonu değişkene atarsanız, kaldırma kuralı artık fonksiyonun değil değişkenin kuralıdır:
hesapla(); // TypeError: hesapla is not a function
var hesapla = function () { return 42; };
Burada hesapla ismi kaldırılmıştır ama değeri hâlâ undefined'dır; undefined'ı çağırmaya çalıştığınız için tür hatası alırsınız.
Küresel kapsamı kirletmemek
Bir değişkeni hiçbir anahtar kelime kullanmadan atarsanız (toplam = 5;), katı olmayan modda o değişken sessizce küresel kapsama yazılır ve dosyanın her yerinden erişilebilir hâle gelir. Aynı ismi başka bir dosyada da kullanırsanız ikisi birbirini ezer ve teşhisi çok zor bir hata çıkar. Dosyanın başına "use strict"; yazmak ya da modül (type="module") kullanmak bu durumu doğrudan hataya çevirir:
"use strict";
function say() {
adet = 1; // ReferenceError: adet is not defined
}
Pratik ipucu: Hoisting'i kodunuzda bir özellik gibi kullanmayın. Değişkenleri kullanacağınız yere en yakın satırda tanımlayın ve yardımcı fonksiyonları çağrıldıkları yerin üstüne koyun. Böylece dosyayı yukarıdan aşağıya okuyan biri, motorun iki aşamalı davranışını bilmeden de kodu doğru anlar. Kaldırma bilgisi asıl olarak başkasının yazdığı tuhaf davranan kodu teşhis ederken işinize yarar.