Variable ve Lexical Environment Nedir? Scope Chain Bu İşin Neresinde?
Java Script’in Temel Kavramları
Bir önceki yazımda Execution Stack ve Execution Context kavramlarına değinmiştim. Bu yazıyı okumadan önce aşağıdaki blog yazıma göz atmanızı tavsiye ederim.
Eğer ben zaten okumuştum diyorsanız o halde kaldığımız yerden devam etme vaktimiz geldi.
Her fonksiyon çağırıldığında ona ait Execution Context’in, stack içine eklendiğini söylemiştim. Fakat bu Execution Context nasıl yaratılıyor kısmına değinmemiştim. Execution Context içinde this
anahtar kelimesinin atama bilgisi, Variable Environment
ve Lexical Environment
içerik bilgilerinden oluşur.
Creation Stage (Yaratılma Aşaması)
this
anahtar kelimesinin atama işlemi bu aşamada gerçekleşir.- Variable Environment (Değişken Ortamı) bu aşamada tanımlanır ve
var
ile tanımlanan değişken bilgileriundefined
olarak tanımlanır. - Lexical Environment (Anlamsal Ortam) bu aşamada Variable Environment’in kopyasıdır.
Execution Stage (Çalışma Aşaması)
- Tanımlanan değişkenlerin değer atamaları yapılır.
- Lexical Environment diğer fonksiyon bağlamının diğer fonksiyon bağlamlarıyla ilişkilendirmesini yapar
Bu kod parçası çalışırken neler oluyor, ekrana ne, neden yazdırılıyor kısmını görsel üzerinden anlatmaya çalışacağım.
Öncelikle kodumuzun global context, greet ve welcome fonksiyonlarının contextleri olmak üzere 3 ana parçadan oluştuğunu söyleyebiliriz. welcome()
ve greet()
fonksiyonlarının aynı seviyede -global context’e bağlı olarak- tanımlanmıştır. Örnek kod parçasının 10. satırında greet()
fonksiyonu çağırıldığında Execution Stack
’in durumunu resimdeki gibi düşünebiliriz. greet()
fonksiyonun içinde(satır 4) konsol ekranına ‘Hello ’ ve name
değişkenin tanımlı olduğu değeri yazdırmak için bir kod parçası olduğunu görüyoruz. Fakat bir sorun var gibi çünkü greet()
fonksiyonunun contextinde name
değişkeni tanımlanmamış. Bu durumda bir JavaScript kodu nasıl çalışır? Fonksiyonun içinde kullanılan değişkenler öncelikle fonksiyonun kendi contexti içerisinde aranır. greet()
fonksiyonunun Execution Context
’inde name
değişkeni bulunamadığından dolayı greet()
fonksiyonun bağlı olduğu bir üst context olan Global Context
’te olup olmadığı kontrol edilir. Bu örnekte greet()
fonksiyonunun welcome()
fonksiyonun içinden çağırıldığı için eğer ekrana ‘Unknown Guest’ yazdırılacağını düşündüyseniz maalesef yanıldınız.
Gelin şimdi benzer fakat biraz daha karışık bir kod örneğinde ekrana ne yazılacağını adım adım inceleyelim.
Aşağıda bulunan Resim 2 de contextlerin birbiriyle ilişkisini göstermeye çalıştım. Örneğin drive()
fonksiyonunun diğer contextlerle ilişkisine baktığımızda drive()
içinde kullanılan değişkenler ve fonksiyonlar önce drive()
fonksiyonunun kendi contextinde aranır. Bulunamayan sonuçlar için parent context olan buyVehicle()
’ın contextine erişilir. Çünkü drive fonksiyonu buyVehicle()
fonksiyonun contextinde tanımlanmıştır. Burda da bulamayan değişkenler için global context’e erişilir.
Satır 26: ekrana yazdırılmak istenen car
değişkeni içinde bulunulan Global Context içinde tanımlı olduğu için ekrana ilk olarak I have an Audi yazdırılır.
Satır 28: walk()
fonksiyonu çağırılır ve (satır 23) ekrana yazdırılmak istenen place
değişkeni walk()
contextinde olmadığı için parent context olan Global Context içinden okunur ve ekrana I’m going to London yazdırılır.
Satır 29: buyVehicle()
fonksiyonu çağırılır. İki farklı car
ve motorCycle
değişkenleri bu context içinde tanımlanır ve ekrana bu context içinde daha önce tanımlı bir car
değişkeni olduğu için I bought a Mercedes yazdırılır.
Satır 17: drive()
fonksiyonu çağılır. Burada da car
adında bir değişken farklı bir değerle tanımlandıktan (satır 11) sonra ekrana I am driving a BMW yazdırılır. motorCycle
değişkeni tanımlı olmadığından dolayı parent context olan buyVehicle()
contextinden okunur ve ekrana (satır 12) I have a Yamaha yazdırılır.
Satır 13: ekrana yacht
değişkeni kullanılarak I have a ... yazdırılmak istenir fakat bu context içinde yacht
değişkeni tanımlı olmadığından dolayı parent context olan buyVehicle()
contextine erişilir. yacht
değişkeni burada da tanımlı olmadığından Global Context’e erişilip bu değişken aranır. Fakat burada da yacht
ismiyle bir değişken tanımlanmadığı için ReferenceError: yacht is not defined
hatası fırlatılır.
Not: walk()
contexti içinde tanımlı bir yacht
değişkeni vardır fakat bu contextler arasında bir bağlantı olmadığı için bu değişkene erişim sağlanamaz.
Özetlemek gerekirse Variable Environment
her fonksiyonun kendi içinde tanımlanan fonksiyonların ve değişken değerlerinin saklandığı yer. Lexical Environment
ise bir context içinde tanımı bulamayan bir değişkenin hangi contexte araması gerektiğinin adresinin tutulduğu yapı olarak düşünülebilir. Contextler arasındaki bu zincirli ilişki de Scope Chain
olarak adlandırılır. Bir sonraki blog yazısında görüşmek üzere.
Kaynaklar: