JavaScript: Bu ne perhiz, what is “this” Aman İsmail, can touch “this”

0 1,544

Merhaba bu yazımda; Javascript’te anlaşılması en karışık konulardan biri olan this anahtar sözcüğünden bahsedeceğim. Konuya geçmeden başlığa adını veren Grup Vitamin’in İsmail şarkısını dinlemek isterseniz sizi şuraya alalım.

Image for post

Yazıya direkt olarak bir örnekle başlamak istiyorum. Aşağıdaki örnekte kisi nesnesinin içerisinde bulunan yasHesapla fonksiyonunu kullanarak, yaş bilgisini ekrana yazdırıyoruz. Çıktıya baktığımızda istediğimiz sonuç ekranda yazılmıyor. Garip değil mi? Yazının amacı işte bu garip(!) olan durumun altında yatan gizemi ortaya çıkarmak. Umarım başarabilirim. Hadi başlayalım.

StackBlizt

Javascript, this anahtar sözcüğünü C++ dan ödünç almıştır. Her iki dilde de this anahtar sözcüğü; kendi özel sınıfından türetilmiş nesneye işaret eder. Buraya kadar her şey normal. JavaScript’te this anahtar kelimesinin bir ikinci bir kullanım amacı/özelliği mevcuttur. this anahtar kelimesi bir önceki görevinin yanı sıra Execution Context’i(genellikle bir fonksiyonun nerede çalıştırıldığına bağlıdır) izlemek için de kullanılır. Concext değiştikçe, this anahtar cümlesinin işaret ettiği nesne de değişir. Bu ikilik durumu işlerin karmaşıklaşmasına neden olmaktadır.

this anahtar sözcüğünün kullanımı

  1. this anahtar sözcüğü; Özel bir sınıfın yapıcı metodundan türetilmiş nesneye işaret eder.

StackBlitz

Birinci örnekte Meyve fonksiyonu(Yapıcı Fonksiyon), Meyve tipindeki nesne için yapıcı metot olarak kullanıldı. Bu yüzden this anahtar kelimesi objenin kendisine referans etti. 18. satırdaki kullanım ile; Şu anda tanımladığımız nesne aslına bu(this) nesne diyoruz. Yapıcı bir fonksiyon kullandığımızda, fonksiyonun tamamı yapıcı metot olur. Yukarıdaki bilgiler ışığında konsolda da görüldüğü gibi this anahtar sözcüğü Meyve’nin kendisini işaret etmiştir.

elma nesnesini Meyve nesnesinden türettikten sonra elma.renk özelliğine(property) ulaşabiliriz. Çünkü renk özelliği this anahtar sözcüğüne ilerde yaratılacak her bir örneği için eklendi.

İkinci örnekte de benzer durum gözlenmiştir.

2. this anahtar sözcüğü Execution Context( lexical scope veya lexical environment olarak ta adlandırılır) öğesini izler. Lexical Scope’ı , ilgili kapsamda tüm değişkenler için hafızada ayrılan konum olarak düşünebilirsiniz.

StackBlitz

Birinci örneğimizde this anahtar kelimesi farklı bir duruma büründü. Eğer bir fonksiyonu new ile kullanmayıp sadece çalıştırırsa; this anahtar kelimesi Global Scope’a referans eder. Çünkü varsayılan Execution Context global’dir.(Browserlarda global scope [object Window]’dır). 2. örnekte olduğu gibi bir fonksiyon new anahtar sözcüğü ile kullanırsa, türetilen nesnenin kendisine referans eder.

Basit Fonksiyon çağrısı yapıldığında(new kullanılmadan), this anahtar kelimesi her zaman global nesnesine referans eder

  • Execution Context bağlantısı, bir Callback fonksiyon tarafından belirtildiğinde, this anahtar kelimesi , bir nesnenin yapıcısının içinde tanımlanmış olsa bile kurulur.

StacBlitz

Yukarıdaki örneğimizin 15. satırda çalıştırılan fonksiyonun çıktısındaki undefined kelimesine dikkat etmişsinizdir. Tuhaf değil mi? Önce fonksiyonun içerisinde neler oluyor bunu anlayalım. 3. satırda calistir özelliğini tanımlayıp araba fonksiyonun içindeki 5. satırda bulunan calistir fonksiyonunu kendisine atıyoruz. Bu satırda herhangi bir hata almıyoruz çünkü fonksiyonlar hoisted edildiği için tanımlamadan önce kendisini bir değişkene atayabiliriz. calistir fonksiyonun içinde bulunan setTimeout fonksiyonu ile arabayı parametre olarak verilen süre kadar çalıştırıyoruz.

15. satırdaki durumu açıklarsak. setTimeout fonksiyonunu çağırdığımız zaman fonksiyon, araba nesnesi ile this anahtar kelimesi ile olan bağını koparır ve [object Window]’a referans eder. Bu sorunu çözmek için aşağıdaki gibi bir yöntem kullanabiliriz.

StackBlitz

6. satırda this değişkeni yeni bir değişkene atıyoruz. Çünkü calistir fonksiyonu araba fonksiyonuna referans ettiğinden, araba fonksiyonun tüm özelliklerini yakalayabiliriz.

  • Execution Context’te olan bu bağlantılı durumu, arrow function kullanarak ortadan kaldırabiliriz. Çünkü arrow fonksiyonların yapıcı metodu yoktur. Bu yüzden fonksiyonunda kendine ait bir context’i yoktur. arrow fonksiyonlarda this bir üst bloğa işaret eder.

StackBlitz

6. satırda function() {} ifadesini arrow syntax () => {} ile değiştirdik. Bu sayede let that = this değişken atamasından kurtulmuş olduk.

Yazının başındaki örneğe dönüp orada tuhaf görünen durumu açıklayalım.

StackBlitz

Örneğimizde 14. satırda kisi nesnesinde bir özellik olarak tanımlanmış olan yasHesapla fonksiyonu çağrılıyor. 7. satırda this nesnesi çağrılıp içinde bulunan adi bilgisi ekrana yazılıyor. Bu satırda this nesnesi kisi nesnesine referans ettiğinden hata almadan adi özelliğine ulaşılabilmiştir. yasHesapla fonksiyonun içerisinde, 5. satırda yasiYaz fonksiyonu tanımlanıyor ve 11. satırda bu fonksiyon çağrılıyor(basit fonksiyon çağrısı). Bu fonksiyonun içerisindeki thisglobal nesnesine referans ettiğinden ve global nesnesi içerisinde yasi özelliği bulunmadığından undefined olarak ekrana yazılmıştır. Bu durum JavaScript’in bir bugı değil. Kural açık, basit fonksiyon çağrısı yapıldığında(new kullanılmadan) this nesnesi her zaman global nesnesine referans eder.

(İsteğe bağlı okuma bölümü)JavaScript’te her fonksiyonda varsayılan olarak bulunan callbind ve apply metotları ile this anahtar sözcüğünün nasıl davranış sergilediğine yakından bakalım.

StackBlitz

callapplybind metotları kendisine verilen parametreleri this nesnesinin yeni değerlerini sunar. Bu sayede bir metodu, kendisine parametre olarak verilen nesneyi inherit ederek, aynı metodu tekrar yazmadan kullanabilmemize olanak sağlar. Konuyu daha iyi anlamak için aşağıdaki örneğe bakalım:

StackBlitz

Yukarıdaki örnekte Araba nesnesinin hesapla fonksiyonu bulunmamaktadır. hesapla fonksiyonu call ile inherit olmuş ve this nesnesi Araba nesnesi için değerlerini sunmuştur.

KAPANIŞ

JavaScript’teki bu tarz konseptleri anlamak biraz zaman alır. O yüzden bol bol pratik yapmak gerekir.

Yazının içerisinde eksik, hatalı bir durumsa iletirseniz düzeltirim. Bir sonraki yazıda görüşmek üzere.

Email adresiniz yayınlanmayacaktır.