JavaScript Closures ve Scope: Kapsam Zinciri

JavaScript Closures ve Scope: Kapsam Zinciri
Closure, JavaScript'in en güçlü ve en çok yanlış anlaşılan kavramlarından biridir. Bir fonksiyonun, tanımlandığı kapsamdaki değişkenlere — o kapsam sona erdikten sonra bile — erişebilmesi anlamına gelir. Scope (kapsam) zinciri ile birlikte closure'lar, modül pattern'leri, veri gizleme ve fonksiyon fabrikaları gibi birçok ileri düzey tekniğin temelini oluşturur.
1. Scope (Kapsam) Türleri
JavaScript'te üç temel kapsam türü vardır: global kapsam, fonksiyon kapsamı ve blok kapsamı. Her kapsam, değişkenlerin erişilebilirlik sınırlarını belirler.
// Global kapsam
const globalDegisken = "Her yerden erişilebilir";
function disKapsam() {
// Fonksiyon kapsamı
const fonksiyonDegiskeni = "Sadece bu fonksiyonda erişilebilir";
if (true) {
// Blok kapsamı (let ve const)
let blokDegiskeni = "Sadece bu blokta erişilebilir";
var varDegiskeni = "Fonksiyon kapsamında erişilebilir (var)";
console.log(globalDegisken); // ✅ Erişilebilir
console.log(fonksiyonDegiskeni); // ✅ Erişilebilir
console.log(blokDegiskeni); // ✅ Erişilebilir
}
console.log(varDegiskeni); // ✅ var blok kapsamına uymaz
// console.log(blokDegiskeni); // ❌ ReferenceError
}
// Kapsam zinciri arama sırası
const x = "global";
function dis() {
const x = "dış fonksiyon";
function ic() {
// const x = "iç fonksiyon"; // Eğer burada tanımlı değilse...
console.log(x); // "dış fonksiyon" — kapsam zincirinde yukarı arar
}
ic();
}
dis();
2. Closure'ın Temelleri
Bir fonksiyon, başka bir fonksiyonun içinde tanımlandığında, dış fonksiyonun değişkenlerine referans tutar. Dış fonksiyon tamamlansa bile bu referanslar korunur — işte closure budur.
// Temel closure örneği
function sayacOlustur() {
let deger = 0; // Closure ile korunacak değişken
return {
artir() { return ++deger; },
azalt() { return --deger; },
degerGetir() { return deger; }
};
}
const sayac = sayacOlustur();
console.log(sayac.artir()); // 1
console.log(sayac.artir()); // 2
console.log(sayac.azalt()); // 1
console.log(sayac.degerGetir()); // 1
// 'deger' değişkenine dışarıdan doğrudan erişim yok!
// console.log(deger); // ❌ ReferenceError
// Her çağrı yeni bir closure oluşturur
const sayac2 = sayacOlustur();
console.log(sayac2.degerGetir()); // 0 (bağımsız kapsam)
3. Closure Kullanım Alanları
Closure'lar birçok önemli programlama pattern'inin temelini oluşturur. İşte en yaygın kullanım senaryoları:
// 1. Veri gizleme (Encapsulation)
function oturumYoneticisi() {
let token = null;
let sonErisim = null;
return {
girisYap(yeniToken) {
token = yeniToken;
sonErisim = Date.now();
console.log("Giriş başarılı");
},
tokenGetir() {
if (!token) return null;
sonErisim = Date.now();
return token;
},
cikisYap() {
token = null;
sonErisim = null;
console.log("Çıkış yapıldı");
}
};
}
// 2. Fonksiyon fabrikası
function carpanOlustur(carpan) {
return function(sayi) {
return sayi * carpan;
};
}
const ikiKati = carpanOlustur(2);
const ucKati = carpanOlustur(3);
console.log(ikiKati(5)); // 10
console.log(ucKati(5)); // 15
// 3. Memoization (Önbellekleme)
function memoize(fn) {
const onbellek = new Map();
return function(...args) {
const anahtar = JSON.stringify(args);
if (onbellek.has(anahtar)) {
console.log("Önbellekten döndürülüyor");
return onbellek.get(anahtar);
}
const sonuc = fn.apply(this, args);
onbellek.set(anahtar, sonuc);
return sonuc;
};
}
const fibonacci = memoize(function(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(40)); // Anında hesaplanır
// 4. Partial application
function partial(fn, ...oncekiArgs) {
return function(...sonrakiArgs) {
return fn(...oncekiArgs, ...sonrakiArgs);
};
}
function log(seviye, tarih, mesaj) {
console.log(`[${seviye}] ${tarih}: ${mesaj}`);
}
const bilgiLog = partial(log, "INFO");
const bugununLogu = partial(bilgiLog, new Date().toLocaleDateString());
bugununLogu("Sunucu başlatıldı"); // [INFO] 27.03.2026: Sunucu başlatıldı
4. Yaygın Closure Tuzakları
Closure'lar güçlü olsa da dikkatli kullanılmazsa beklenmeyen davranışlara neden olabilir.
// Tuzak 1: Döngülerde var ile closure
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Çıktı: 3, 3, 3 (hepsi aynı 'i'ye referans tutar)
// Çözüm 1: let kullanımı
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Çıktı: 0, 1, 2
// Çözüm 2: IIFE ile yeni kapsam
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
// Çıktı: 0, 1, 2
// Tuzak 2: Hafıza sızıntısı
function potansiyelSizinti() {
const buyukVeri = new Array(1000000).fill("veri");
return function() {
// buyukVeri hâlâ bellekte tutulur, kullanılmasa bile
console.log("Merhaba");
};
}
// Çözüm: İhtiyaç duyulmayan referansları temizleyin
function duzeltilmis() {
let buyukVeri = new Array(1000000).fill("veri");
const sonuc = isleVeriyi(buyukVeri);
buyukVeri = null; // Referansı serbest bırak
return function() {
console.log(sonuc);
};
}
5. Modül Pattern'i
Closure'ların en önemli kullanım alanlarından biri, ES6 modülleri öncesinde yaygın olarak kullanılan modül pattern'idir.
// IIFE ile modül pattern'i
const Dogrulayici = (function() {
// Private değişkenler ve fonksiyonlar
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const telefonRegex = /^(\+90|0)?[0-9]{10}$/;
function temizle(deger) {
return String(deger).trim();
}
// Public API
return {
emailDogrula(email) {
return emailRegex.test(temizle(email));
},
telefonDogrula(telefon) {
return telefonRegex.test(temizle(telefon).replace(/\s/g, ""));
},
zorunluAlanDogrula(deger) {
return temizle(deger).length > 0;
}
};
})();
console.log(Dogrulayici.emailDogrula("test@ornek.com")); // true
console.log(Dogrulayici.telefonDogrula("+905551234567")); // true
// Dogrulayici.emailRegex; // undefined (private)
import/export) tercih edilse de, modül pattern'ini anlamak closure'ların gücünü kavramak ve eski kod tabanlarıyla çalışmak için hâlâ çok değerlidir.
Sonuç
Closure ve scope kavramları JavaScript'in temel yapı taşlarıdır. Kapsam zincirinin nasıl çalıştığını, closure'ların değişken referanslarını nasıl koruduğunu ve bu mekanizmayı veri gizleme, memoization, fonksiyon fabrikaları ve modül pattern'i gibi ileri düzey tekniklerde nasıl kullanabileceğinizi bilmek, profesyonel JavaScript geliştirmenin olmazsa olmazıdır. Yaygın tuzaklardan kaçınarak closure'ları bilinçli şekilde kullanın.