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

En dışarı this yazdığımızda..

Fonksiyon içerisinde → this

Bir fonksiyon oluşturup onun içeriside this eriştiğimizde yine this globaldeki this olduğunu görebilirsiniz.

function a() içerisinde this
Anonymous function içerisinde
Arrow function içerisinde
IIFE function içinde

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.

iç içe fonksiyon çağrımı

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.

Object içerisinde this

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.

Object içerisinde bir fonksiyon içerisinde this

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.

Self kullanımı.

Array içerisinde → this

Array içerisinde direk this yazdığınızda o Global this referans tutar.

Array içerisinde this kullanımı

Ama array içerisindeki bir fonksiyonda ise this o array referans olarak gösterir.

Array içerisinde this

Class içerisinde → this

Class içerisindeki bir metod içerisinde this o sınıfın kendisine erişim hakkı tanır.

Class içerisinde this kullanımı

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.

call/apply kullanımı

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.

sayHello cağrımı ve this’in durumu

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);
bind ile this ekleme..

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.

sayHello fonksiyonunu arrow olarak yazmak
sayHello başka bir arorow fonksiyon ile wrap edecek şekilde çağırmak

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 kullanımı…

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.

new kullanımı sonrasında fonksiyon içerikleri

Referanslar

  • Javascript: Understanding the Weird Parts

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.

--

--