JAVASCRIPT’IN TARIHÇESI
JavaScript’te this Ne Anlama Geliyor ?
JavaScript’de en çok karıştırılan konularından bir tanesi this anahtar kelimesinin kullanımıdır. Kod geliştirirken this sıkça kullanırız ama ne değeri aldığını tam olarak bilemeyiz. Bu yazıda farklı farklı durumlarda this nasıl çalıştığını anlatmaya çalışacağım. This konusu ile ilgili olduğu içinde bind, call ve apply konularından da bahsedeceğim.
Javascript’de this kavramını anlatmadan önce Execution Context ve Lexical Environment kavramlarını anlamanız gerekiyor. Bu konulardan bilgi sahibi değilseniz öncelikle bu yazımı okumanızı öneririm.
Kodumuz çalıştırılırken en dıştaki context (Global Context) ve her çağrılan fonksiyonda Call Stack ayrı bir Execution Context oluşturulduğudan bahsetmiştim. Her fonksiyonun execution context içerisinde;
- variables env (scope kapsamındaki değişkenleri tutmak için)
- outer env (kendi scope bulamadığı değişkenleri lexical üst env arayıp bulmak için
- this (değişkenleri ve fonksiyonları bağladığı context)
- code fonksiyonun kodu
bu kavramların bulunduğunu anlatmıştım. Ama this context her zaman koddaki lexical scope göre mantıksal bir değer almaz. Bu değerleri neye göre aldığını aşağıdaki farklı durumlara göre açıklamaya çalıştım.
A. Kodun Farklı Yerlerinde this Hangi Değerleri Alır ?
Global’de → this
Fonksiyon içerisinde → this
Bir fonksiyon oluşturup onun içeriside this eriştiğimizde yine this globaldeki this olduğunu görebilirsiniz.
Durumu iyice karmaşıklaştırıp iç içe bir sürü fonksiyon olduğunda this değişkeni hangi değeri aldığına bakalım. Aşağıdaki resimde ne kadar iç içe fonksiyon tanımlasakta this fonksiyonun hep Global’daki this referans tuttuğunu görebilirsiniz.
Obje içerisinde → this
Obje içerisinde fonksiyon tanımladığımızda this o objeyi namespace alacak şekilde this alır. Örneğin aşağıdaki resimde sayHello içerisinde this baktığımızda Global this referans tutmaz.
Objenin içerisinde bir fonksiyon daha tanımlayıp onun içerisinde this yazdığımızda bir üst lexical olması gereken this değilde Global’deki this referans verdiğini görebilirsiniz. Bu durum bizim istediğimiz bir durum değildir. Ama JS Engine bu durumu bu şekilde ele aldığı için buna kendinizce bir çözüm üretmeniz gerekir.
Bu durumda scope kavramından da hatırlayacağınız gibi this istediğiniz bir noktadan itibaren self=this veya _this=this gibi eşitlemeler yaparak artık bu self / _this değişkeni üzerinden işlemlerinizi yapabilirsiniz.
Array içerisinde → this
Array içerisinde direk this yazdığınızda o Global this referans tutar.
Ama array içerisindeki bir fonksiyonda ise this o array referans olarak gösterir.
Class içerisinde → this
Class içerisindeki bir metod içerisinde this o sınıfın kendisine erişim hakkı tanır.
B. apply ve call ne işe yarıyor ?
Spread konusunu anlattığım bu yazıda. Javascript call ve apply kullanımına değiniştim. Call fonksiyonu verilen context ile birlikte parametreleri tek tek vererek çağırmanızı sağlarken apply bu işlemi array olarak yapmanıza olanak sağlar. Yani bir nevi function() invoke etmenin başka başka yolu diyebiliriz.
function sum(x,y,w,z){
let toplam=x+y+w+z; return toplam;
}console.log(sum.call(this,3,5,7,9)); //24
console.log(sum.apply(this,[3,5,7,9])); /24
Spread ile birlikte yukarıdaki işlemi direk call ile yapabilir hale gelmiş olduk. array yayma özelliği bunu sağlamış oldu.
console.log(sum.call(this,...[3,5,7,9]));
Ama this parametresini hiç anlatmamışız. Aşağıdaki örnekte göreceğiniz gibi ben bir fonksiyonu çağırırken call/apply çağırdığımızda this context değiştirebiliyor olmak bize Function barrowing ile başka sınıflarında veya objelerin içerisinde fonksiyonları kullanabilme imkanı sağlar.
C. bind ne işe yarıyor ?
bind konusunu apply/call ayrı ele almak istedim çünkü React kullanıcılarının sıklıkla Component eventlerini bind ettiğinde eğer metodlarını sayHello ile bind etmez ise this artık global olduğu için burda aranan değer undefined gelmaktedir. Aşağıdaki örnekte direk context(onur) ile çağrıldığında sorun çıkmıyor. Ama bir async bir event bağlanıp callback çağrıldığunda this global olduğu için sorun çıkarıyor.
Bu durumu çözmenin bir kaç yöntemi bulunur.
Yöntem:1 constructor içerisinde this tekrardan bind etmek
Kodu aşağıdaki gibi yazdığımızda ilgili fonksiyonun her zaman this context olarak sınıfı almasını zorlamış oluyoruz.
this.sayHello=this.sayHello.bind(this);
Yöntem 2: sayHello arrow function yazmak
Arrow fonksiyonlar diğer fonksiyonlarda olduğu gibi içerlerinde this, arguments, super, new.target yapılarını bulundurmaz. Bu durumda bir üst scope’dan this arandığında otomatik olarak sınıf this kullanacağı için bu sorun ile karşılaşmayız.
D. new ile birlikte fonksiyon Nasıl davranır ?
Yukarıdaki gibi Obje oluşturabildiğimiz gibi new keyword bellekte bir object alanı oluşturabiliriz. aşağıda uOnur ve uDeniz ikisinde new olmadan oluşturduğumuzda this → window olduğu ikiside aynı context üzerinde windows üzerinde çalışacak uDeniz name ilk yazılan onur ismini ezecektir.
window.name: 'deniz'// yazacaktır
new ile oluşturduğumuz objelerin bellek alanlarında ilgili isimleri tuttuğunu görebilirsiniz. Artık bu fonksiyon içerisindeki this kendisine ait bir fonksiyon context oluşmuştur.
Referanslar
Okumaya Devam Et 😃
Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.