JAVASCRIPT SCOPE CLOSURE ÖRNEKLEMEK
JavaScript mülakatlarında en sık sorulan iki kavram: scope ve closure. Bu iki kavramı anlamadan modern JavaScript yazılamaz; modüller, async kod, framework'lerin çoğu altta bu mekanizmaları kullanır. Closure özellikle React hooks gibi yapıların temelinde durur; closure'ı bilmeden useState'in nasıl çalıştığı anlaşılmaz.
Scope basitçe "değişken hangi alanda görünür" sorusunu cevaplar. Closure ise "bir fonksiyon dışındaki değişkenlere nasıl erişir" sorusunu. İkisi birlikte JavaScript'in en güçlü ama en kafa karıştırıcı özelliklerinden; kavramların kesin tanımları için web teknolojileri dokümantasyonu ayrıntılı örnekler içerir.
Closure'ı anlamanın ön koşulu scope'u anlamaktır: önce scope türleri, sonra zincirin nasıl tırmandığı (scope chain), en sonda da fonksiyonun doğduğu ortamı hatırlaması — yani closure'ın kendisi. Pratik örnekler bu sıranın üzerine geldiğinde mekanizma ezber olmaktan çıkar.
Scope nedir?
Bir değişkenin görünür olduğu kod alanı. JavaScript'te üç scope türü var:
1. Global scope
Tüm dosyada görünür; en üst seviye.
const isim = 'Ahmet'; // global scope
function selamla() {
console.log(isim); // erişebilir
}2. Function scope
Fonksiyon içinde tanımlanan değişkenler sadece o fonksiyon içinde görünür.
function hesapla() {
const sonuc = 42; // function scope
console.log(sonuc); // OK
}
console.log(sonuc); // HATA: sonuc tanımsız3. Block scope
let ve const ile tanımlanan değişkenler süslü parantez { } içinde görünür.
if (true) {
let x = 10; // block scope
}
console.log(x); // HATA
// var farklı; function scoped
if (true) {
var y = 10; // function veya global scope
}
console.log(y); // 10 (erişilebilir)var, let, const farkı
| Özellik | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisting | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |
| Redeclare | İzin var | İzin yok | İzin yok |
| Reassign | İzin var | İzin var | İzin yok |
Modern pratik: const varsayılan; reassign gerekiyorsa let; var kullanma.
Scope chain
İç içe fonksiyonlarda değişken arama: en içten dışa doğru.
const a = 1; // global
function disFonksiyon() {
const b = 2; // disFonksiyon scope
function icFonksiyon() {
const c = 3; // icFonksiyon scope
console.log(a, b, c); // 1, 2, 3
// a global'dan, b dış fonksiyondan, c kendi scope'tan
}
icFonksiyon();
}icFonksiyon a'yı doğrudan bulamaz; scope chain ile yukarı çıkıp önce disFonksiyon'da bakar, sonra global'a bakar. Bulduğu ilk eşleşmeyi alır.
Closure nedir?
Bir fonksiyonun, kendisi tanımlandığı scope'taki değişkenlere erişebilmesi. Fonksiyon dışarı çıkarılsa bile o değişkenlere erişim devam eder.
function sayacOlustur() {
let sayac = 0;
return function() {
sayac++;
return sayac;
};
}
const arttir = sayacOlustur();
console.log(arttir()); // 1
console.log(arttir()); // 2
console.log(arttir()); // 3sayacOlustur fonksiyonu bittikten sonra bile dönen fonksiyon "sayac" değişkenine erişebiliyor. Bu closure'dur; dış fonksiyonun scope'unu "kapatıp" içeriye getiriyor.

Closure kullanım örnekleri
1. Private değişkenler
JavaScript'te native private değişken yoktu (modern class # syntax'ı hariç); closure ile simüle edilir.
function bankaHesabi(baslangic) {
let bakiye = baslangic; // dışarıdan görünmez
return {
yatir: (miktar) => { bakiye += miktar; },
cek: (miktar) => {
if (miktar > bakiye) return 'Yetersiz';
bakiye -= miktar;
return bakiye;
},
sorgu: () => bakiye
};
}
const hesap = bankaHesabi(1000);
hesap.yatir(500);
console.log(hesap.sorgu()); // 1500
console.log(hesap.bakiye); // undefined - dışarıdan erişim yok2. Currying
Bir fonksiyonu parça parça çağırma; her aşamada bir argüman alıp yeni fonksiyon döner.
function carpan(x) {
return function(y) {
return x * y;
};
}
const ikiyleCarp = carpan(2);
const beslyeCarp = carpan(5);
console.log(ikiyleCarp(10)); // 20
console.log(beslyeCarp(10)); // 503. Event handler'larda state
function butonHazirla() {
let tiklamaSayisi = 0;
document.querySelector('button').addEventListener('click', () => {
tiklamaSayisi++;
console.log(`Tıklama: ${tiklamaSayisi}`);
});
}
butonHazirla();
// Buton tıklandığında tiklamaSayisi closure ile korunur4. setTimeout closure
function gecikmeliMesaj(mesaj, ms) {
setTimeout(() => {
console.log(mesaj); // closure ile mesaj'a erişir
}, ms);
}
gecikmeliMesaj('Merhaba', 1000);
// Fonksiyon biter ama setTimeout callback'i mesaj'ı görürClosure tuzakları
1. for döngüsünde var ile closure sorunu
// Yanlış: var function-scoped
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Çıktı: 3, 3, 3 (beklenen 0, 1, 2 değil)
// Sebep: tüm callback'ler aynı i'yi paylaşır
// Doğru: let block-scoped
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Çıktı: 0, 1, 2 (her iterasyonda yeni i)2. Memory leak riski
Closure dış scope'a referans tutar; o scope'taki tüm değişkenler bellekte kalır. Büyük objeleri yanlış closure'a sokmak memory leak yaratır.
function bigDataIslem() {
const buyukVeri = new Array(1000000).fill('x');
return function() {
console.log('İşlem yapıldı');
// buyukVeri kullanılmıyor ama closure ile bellekte tutulur
};
}
const handler = bigDataIslem();
// buyukVeri hâlâ bellekte; garbage collect olmazÇözüm: ihtiyaç olmayan değişkenleri closure dışında tut.
Hoisting
JavaScript değişken ve fonksiyon tanımlamalarını scope başına "kaldırır". var ile tanımlananlar undefined ile; let/const ise "temporal dead zone" (TDZ) ile.
console.log(a); // undefined (var hoisted)
var a = 5;
console.log(b); // HATA: TDZ
let b = 10;
selamla(); // OK (function declaration hoisted)
function selamla() {
console.log('Merhaba');
}
selamla2(); // HATA: function expression hoisted ama undefined
const selamla2 = function() {
console.log('Merhaba');
};Lexical vs dynamic scope
JavaScript lexical scope kullanır: bir değişkenin nereden erişilebileceği kod yazılırken belirlenir; çalışma anında değil.
const isim = 'Global';
function selamla() {
console.log(isim); // 'Global' (lexical)
}
function farkliScope() {
const isim = 'Lokal';
selamla(); // hâlâ 'Global' yazar
// Çünkü selamla tanımlandığı yerdeki isim'i görür
}
farkliScope();this ve scope ilişkisi
this dinamik; çağrıldığı bağlama göre değişir. Arrow function'lar this'i kapatır (closure benzeri).
class Sayac {
constructor() {
this.deger = 0;
}
baslat() {
// setInterval callback'i farklı this'e sahip
setInterval(function() {
this.deger++; // HATA: this undefined
}, 1000);
// Arrow function this'i kapatır
setInterval(() => {
this.deger++; // OK: outer this kullanılır
}, 1000);
}
}
Tipik Hatalar
- var kullanmak. Modern JavaScript'te let/const tercih edilir; var bug riski yüksek
- for içinde var ile closure. Klasik soru; let kullanmak çözer
- Global scope kirletme. Modül yapısı kullanmadan global değişken eklemek
- Memory leak. Closure ile büyük objeleri tutmak
- this'in scope ile karıştırılması. this dinamik; scope statik
Konu Üzerinde Derinleşmek
Scope ve closure modern JavaScript'in temel taşları. Konuya hâkim olmak için JavaScript eğitimi programları bu kavramları derinlemesine işler.
Kısa Özet
JavaScript'te scope değişken görünürlüğünü; closure fonksiyon ile değişkenlerin "kapatılmasını" yönetir. Block scope (let/const), function scope (var), global scope üç ana türü. Closure private değişkenler, currying, event handler state'i gibi pratik kullanımlar için temeldir. var yerine let/const, for döngüsünde let, arrow function ile this kapatma modern pratiklerdir. Closure memory leak'e dikkat; gereksiz büyük objeleri kapsam dışında tutun.



