Javascript’te Değişkenler,Kapsam ve Hoisting

Açıkcası bu yazı boyunca scope ve variable’ın türkçe karşılıklarını kullanıp kullanmamak konusunda oldukça karasız kaldım.Hatta birkaç kez yazıyı baştan sona değiştirmek zorunda kaldım.Scope için kapsam ifadesinin oldukça yetersiz kaldığına inanıyorum.Ancak her iki kelimeyi türkçe kullanmak tutarlı olacaktır.

Javascript’te kapsamı basit görebilirsiniz ancak düşündüğümüzden farklı sonuçlar görmeye hazır olun.

Javascript’te kapsam

Javascriptte kapsamı ele almadan ilk olarak bir örneği inceleyelim.

var isim = "Hakan ERSU";
function merhaba(){
	var isim = "Çilem ERSU";
	console.log("Merhaba "+isim);
}
merhaba();
console.log("Merhaba "+isim);

Bu script bloğumuzun sonucunda çıktı olarak aşağıdaki sonucu alacağız.

"Merhaba Çilem ERSU"
"Merhaba Hakan ERSU"

Sonucumuzun beklediğimiz gibi olduğunu söyleyebiliriz.Bunun nedeni javascript’te fonksiyon seviyesinde kapsama ( function scope‘a ) sahip olmasıdır.Bunun tersine birçok programlama dilinde block-level kapsam bulunmaktadır.

Yazımın ilerleyen kısımlarında bu kavramlardan bahsedeceğim için biraz olsun bu kavramları açıklamak istiyorum.

Block-Level Scope

Blok seviyesinde kapsam genel olarak akış kontrolü ifadeleri ( if,else,while,for,foreach vs ) arasında tanımlanan değişkenlerin sadece bu kontroller içinde kullanılmasını sağlayan yöntemdir.Bu gibi dillere örnek olarak C ailesi dilleri gösterebiliriz.

#include <stdio.h>
#include <string.h>
main() {
    char *isim="Hakan ERSU";
	printf("%s, ", isim); // 1
	if (1) {
		char *isim="Cilem ERSU";
		printf("%s, ", isim); // 2
	}
	printf("%s\n", isim); // 1
}

Sonuç olarak aşağıdaki gibi çıktı alacağız.

"Hakan ERSU"
"Cilem ERSU" 
"Hakan ERSU"

Aynı örneği javascript ile incelersek;

var isim = "Hakan ERSU";
console.log(isim);
if(true){
	var isim = "Çilem ERSU";
	console.log(isim);
}
console.log(isim);

Sonucumuz aşağıdaki gibi olacaktır;

"Hakan ERSU"
"Çilem ERSU"
"Çilem ERSU"

Javascript’te blok seviyesinde kapsam olmadığını söyleyebiliriz.( Non Block-Level Scope )

Function-Level Scope

Fonksiyon seviyesinde kapsam değişkenlerin global kapsamından etkilenmeden fonksiyon kapsamında kullanılabilmesi demektir.İlk örneğimizde bunu görmüştük ancak başka bir örnek ile inceleyelim.

var isim = "Hakan ERSU";
console.log(isim);
function merhaba(){
	var isim = "Çilem ERSU";
	console.log("Merhaba "+isim);
}
function gulegule(){
	var isim = "Mehmet ERSU";
	console.log("Güle güle "+isim);
}
merhaba();
gulegule();
console.log(isim);

Sonuç;

"Hakan ERSU"
"Merhaba Çilem ERSU"
"Güle güle Mehmet ERSU"
"Hakan ERSU"

Javscript Kapsamı Hakkında Detaylar ( Hoisting )

var isim = "Hakan ERSU";
function merhaba(){
	if(!isim){
		var isim = "Çilem ERSU";
	}
	console.log("Merhaba "+isim);
}
merhaba();

Yukarıda garip ama javascriptin güçlü yanlarından biri kabul edilen bir davranışa tanık olmaktasınız.Yukarıdaki ifade sonuç olarak “Merhaba Çilem ERSU” yanıtını verecektir.Ama JSHint kullanıyorsanız aşağıdaki uyarıları alacaksınız ;

Line 4: var isim = "Çilem ERSU"; --- 'isim' is already defined.
Line 6: console.log("Merhaba "+isim); --- 'isim' used out of scope.

Bu garip davranışın temelinde aslında basit bir neden yatmakta.Eğer bir fonksiyonda global kapsamda bir değişken kullanmaya çalışırsak bunda herhangi bir sorun yoktur.

var isim = "Hakan ERSU";
function merhaba(){
	console.log("Merhaba "+isim); // İsim global kapsamda.
}
merhaba();

Ancak fonksiyon içerisinde konsola yazdırma işleminden sonra aynı isimde bir değişken tanımlarsak konsol çıktımız “Merhaba undefined” olacaktır.Bunun başlıca nedeni siz bir değişkene fonksiyon içerisinde değer tanımladığınızda javascript bu değeri sizin için fonksiyonun en başında oluşturmuş olacaktır.Yani aşağıdaki gibi bir kodunuz varsa ;

var isim = "Hakan ERSU";
function merhaba(){
	console.log("Merhaba "+isim); // İsim global kapsamda.
    var isim = "Çilem ERSU";
}
merhaba();

Javascript kodunuzu şöyle görecektir.

var isim = "Hakan ERSU";
function merhaba(){
    var isim;
    console.log("Merhaba "+isim);
    isim = "Çilem ERSU";
}

Artık detaylar başlığı altında verdiğimiz fonksiyonumuz biraz daha anlamlı hale gelmiş olmalı.Javascript verdiğimiz örnek kodu aşağıdaki gibi görecektir

var isim = "Hakan ERSU";
function merhaba(){
    var isim;
	if(!isim){ // isim artık tanımsız yani if işlemi doğru
		isim = "Çilem ERSU";
	}
	console.log("Merhaba "+isim);
}
merhaba();

Sanırım artık oldukça mantıklı görünmekte ve bu davranışa hoisting denilmektedir.Bu davranış fonksiyon içinde tanımlanan başka fonksiyonlarda da geçerlidir ancak detayına şuan girmeyeceğim.

Umarım javascript kapsam hakkında kafanızı daha da karıştırmamışımdır.