Scope (kapsam), bir değişkenin kodun hangi bölümünden görülebildiğini belirleyen kurallar bütünüdür. JavaScript'te dört kapsam türü vardır: global kapsam, fonksiyon kapsamı, let/const/class için blok kapsamı ve ES modüllerinde modül kapsamı. Bunları birbirine bağlayan yapı ise sözcüksel (lexical) kapsam zinciridir. Bir değişken arandığında motor önce en içteki kapsama bakar, bulamazsa dışa doğru ilerler; zincirin hangi sırayla kurulacağını kodun nerede yazıldığı belirler, nerede çağrıldığı değil.
Bu yazıda her kapsam türünü Node.js 24'te çalıştırılmış örneklerle anlatıyoruz. var, let ve const farkının tamamı değişken tanımlama yazısında, tanımdan önce erişim ve TDZ konusu ise hoisting yazısında ayrıca ele alınıyor; burada odak, kapsamların nasıl iç içe geçtiğidir.
Global kapsam ve fonksiyon kapsamı

Hiçbir fonksiyonun, bloğun ya da modülün içinde olmayan bildirimler global kapsamdadır ve her yerden okunabilir. Bir fonksiyon ise kendi kapsamını oluşturur: İçinde tanımlanan değişkenler dışarıdan görünmez, ama fonksiyon dışarıdakileri görebilir. MDN bunu iç fonksiyon için bir tür kapsülleme (encapsulation) olarak anlatır:
const site = "keydal";
function rapor() {
const ziyaret = 42;
return `${site}: ${ziyaret}`;
}
console.log(rapor()); // keydal: 42
console.log(typeof ziyaret); // undefinedtypeof tanımlı olmayan bir ad için hata fırlatmaz, "undefined" döndürür; bu yüzden örnekte değişkenin dışarıdan görünmediğini güvenle gösterebildik. Doğrudan console.log(ziyaret) yazsaydınız ReferenceError alırdınız.
Blok kapsamı: let, const ve var farkı
Süslü parantezlerle oluşturulan bir blok (if, for, tek başına { }) let, const ve class için yeni bir kapsam oluşturur. var ise blokları tanımaz; en yakın fonksiyona ya da global kapsama aittir. MDN, try...catch, switch ve for başlıklarının da var için kapsam oluşturmadığını belirtir:
function blokTesti() {
if (true) {
var a = "var";
let b = "let";
const c = "const";
}
console.log(a); // var
console.log(typeof b, typeof c); // undefined undefined
}
blokTesti();
let x = 1;
{
let x = 2;
console.log("blok içi:", x); // blok içi: 2
}
console.log("blok dışı:", x); // blok dışı: 1İkinci bölümde içteki x, dıştakini gölgeler (shadowing): Aynı ad, iç kapsamda yeni bir değişken olarak tanımlanır ve blok bittiğinde dıştaki değişken olduğu gibi kalır. Bloklar, IIFE'lere benzer şekilde geçici değişkenlerin global kapsamı kirletmesini önlemek için de kullanılabilir.
Sözcüksel kapsam ve kapsam zinciri

JavaScript sözcüksel (lexical, statik) kapsam kullanır: Bir fonksiyonun hangi değişkenleri göreceği, fonksiyonun kaynak kodda nereye yazıldığına göre belirlenir. İç içe fonksiyonlarda her iç fonksiyon, dışındaki tüm kapsamlara erişir; MDN buna kapsam zinciri (scope chaining) der:
function A(x) {
function B(y) {
function C(z) {
return x + y + z;
}
return C(3);
}
return B(2);
}
console.log(A(1)); // 6C, B'nin y parametresini ve A'nın x parametresini görür. Tersi doğru değildir: A, B ya da C içindeki değişkenlere erişemez. Aynı ad farklı kapsamlarda tanımlıysa en içteki kazanır, çünkü arama içten dışa doğru yapılır:
const deger = "global";
function dis() {
const deger = "dış";
function ic() {
const deger = "iç";
return deger;
}
return [ic(), deger];
}
console.log(dis(), deger); // [ 'iç', 'dış' ] globalSözcüksel kapsamın en önemli sonucu, fonksiyonun çağrıldığı yerin değişken aramasını etkilememesidir. Aşağıdaki goster fonksiyonu, kendisini çağıran fonksiyonun yerel x değişkenini değil, tanımlandığı yerdeki x değişkenini görür:
const x = "tanımlandığı yer";
function goster() {
return x;
}
function cagir() {
const x = "çağrıldığı yer";
return goster();
}
console.log(cagir()); // tanımlandığı yerSpesifikasyonda kapsam: Environment Record
ECMAScript spesifikasyonu kapsamı Environment Record adlı bir yapıyla tanımlar. Bir fonksiyon bildirimi, blok ya da catch bölümü her değerlendirildiğinde yeni bir Environment Record oluşur ve o koddaki ad bağlamalarını tutar. Her kaydın [[OuterEnv]] adlı bir alanı, yani dıştaki kayda bir referansı vardır; kapsam zinciri bu referansların arka arkaya izlenmesidir. Global kaydın dış referansı null olduğu için zincir orada biter. Modül kayıtlarının dış ortamı ise global kayıttır. Spesifikasyon bu kayıtların yalnızca tanımlama aracı olduğunu, programın bunlara doğrudan erişemeyeceğini de belirtir.
Bir fonksiyon oluşturulduğunda o anki ortama referans tutar; bu yüzden dış fonksiyon bitse bile iç fonksiyon değişkenlere erişmeye devam eder. Bu davranışın adı closure'dır ve closure yazısında ayrıntılı örneklerle anlatılıyor.
Global nesne: var ve let farkı
Klasik bir script'in en üst düzeyinde var ile tanımlanan değişkenler ve fonksiyon bildirimleri global nesnenin (globalThis) özelliği olur. let, const ve class ise global kapsamda olsalar da globalThis üzerinde özellik oluşturmaz. node -e ile kodu script olarak çalıştırdığımızda fark görünür:
// node -e ile script olarak çalıştırıldı
var eski = 1;
let yeni = 2;
console.log(globalThis.eski, globalThis.yeni); // 1 undefinedAynı kodu bir dosyaya yazıp node dosya.js ile çalıştırırsanız ikisi de undefined çıkar. MDN'ye göre Node.js CommonJS modüllerinde ve ES modüllerinde en üst düzeydeki bildirimler modüle aittir ve global nesneye eklenmez.
Bir de bildirimsiz atama vardır: Strict olmayan kodda tanımlanmamış bir ada değer atarsanız, değişken sessizce global nesnede oluşur. Strict mode bu hatayı yakalar:
function sayac() {
toplam = 5;
}
sayac();
console.log(globalThis.toplam); // 5
function katiSayac() {
"use strict";
try {
baskaToplam = 5;
} catch (e) {
console.log(e.name + ": " + e.message); // ReferenceError: baskaToplam is not defined
}
}
katiSayac();Modül kapsamı
ES modülünde en üst düzeyde tanımlanan değişkenler yalnızca o modüle aittir; var bile global nesneye eklenmez. Başka bir dosyanın kullanabilmesi için değeri export ile açmanız gerekir. Aşağıdaki iki dosyada sayi değişkeni sayac.mjs içinde gizli kalır:
// sayac.mjs
let sayi = 0;
export const arttir = () => ++sayi;
// ana.mjs
import { arttir } from "./sayac.mjs";
arttir();
console.log(arttir()); // 2
console.log(typeof sayi); // undefined
var modulVar = 1;
console.log(globalThis.modulVar); // undefinedModüller otomatik olarak strict mode'da çalışır. import/export ayrıntıları için ES modülleri yazısına bakabilirsiniz.
Kapsam türleri tablosu

| Kapsam | Ne oluşturur | Hangi bildirimler | Not |
|---|---|---|---|
| Global | Klasik script en üst düzeyi | Tümü | var ve function globalThis özelliği olur |
| Fonksiyon | Her fonksiyon çağrısı | var, let, const, function, class | Parametreler de bu kapsamdadır |
| Blok | { }, if, for, while, try | let, const, class | var blok kapsamını tanımaz |
| Modül | Her ES modülü | Tümü | Global nesneye eklenmez, strict mode |
| Sözcüksel zincir | İç içe yazılan kod | Tümü | Arama içten dışa, tanım yerine göre |
Sık yapılan hatalar
- Blok içinde
varile tanımlanan değişkenin bloğun dışında görünmeyeceğini sanmak. - Tanımlamadan atama yapıp yanlışlıkla global değişken oluşturmak; strict mode bunu
ReferenceErrorile engeller. - Bir fonksiyonun, kendisini çağıran fonksiyonun yerel değişkenlerini göreceğini düşünmek.
- İç kapsamda aynı adla değişken tanımlayıp dıştakini istemeden gölgelemek.
letile tanımlı bir değişkeni aynı kapsamda bildirimden önce kullanmak: Dışarıda aynı adlı değişken olsa bileReferenceError: Cannot access 'ad' before initializationalırsınız.
const ad = "dış";
function test() {
try {
console.log(ad);
} catch (e) {
console.log(e.name + ": " + e.message); // ReferenceError: Cannot access 'ad' before initialization
}
const ad = "iç";
}
test();Sık Sorulan Sorular
Scope ile closure arasındaki fark nedir?
Scope, bir adın nereden görülebildiğini belirleyen kural setidir. Closure ise bir fonksiyonun bu kurallarla erişebildiği dış değişkenleri, dış kapsam bittikten sonra da yanında taşımasıdır. Kısacası closure, sözcüksel kapsamın fonksiyonlar dışarı taşındığında ortaya çıkan sonucudur.
Dinamik kapsam JavaScript'te var mı?
Değişken araması için yok; JavaScript sözcüksel kapsam kullanır. Çağrı anında belirlenen tek yaygın değer this'tir. with ifadesi nesne özelliklerini kapsama ekleyerek bu kuralı karmaşıklaştırır ve strict mode'da kullanılamaz.
IIFE hâlâ gerekli mi?
MDN, IIFE'nin geleneksel kullanımlarının çoğunun modüller ve blok kapsamlı bildirimlerle gereksizleştiğini belirtir. Bir ifadenin ortasında birkaç satırlık hesaplama yapıp sonuç döndürmek gibi durumlarda hâlâ kullanılabilir.
Fonksiyon parametreleri hangi kapsamdadır?
Parametreler fonksiyonun kapsamındadır. Default parametre kullanıldığında ise MDN'ye göre parametre başlatıcıları fonksiyon gövdesinin üstündeki ayrı bir kapsamda çalışır; bu yüzden gövdede tanımlanan değişkenleri göremez. Ayrıntılar default ve rest parametreler yazısında.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: JavaScript öğrenme rehberi · Closure nedir · var, let ve const farkı · Hoisting ve TDZ · Strict mode · ES modülleri