Javascript’in Tarihçesi

Neden ? Arrow Functions

Javascript bir çok fonksiyon türü varken neden Arrow (→) kullanımına ihtiyaç duyduk ?

--

Giriş

Bu yazıyı daha önceden yazmış olduğum Javascript’in Tarihçesi yazısının bir devamı olarak yazıyorum. Bir çok kavramı tek bir yazıda ele almanın yaratacağı karmaşıklıktan kaçmak için bu yönteme başvurdum. Bu yazılardaki amacım önceden Javascript’in varolan hangi özelliklerinin yetmediğini ve bu geliştirmeyle neyi hedeflediklerini anlatacağım.

Kısa bir dip not olarak şunuda belirteyim ki, aslında bu konu teknik olarak çok daha derin bir konu Scoping, Pass By Value/Reference, Execution Context ve this, bindings, Callback Hell, Async, Promise vb konuları içeriyor. Ben burada işleri çok karıştırdığı için sadece işlevsel olarak amacından bahsedeceğim teknik derinliklere pek inmeyeceğim.

Özetle aşağıdaki kapsamları anlatmaya çalışacağım.

  • Mevcut Fonksiyon Türleri.
  • Arrow Fonksiyon Nasıl Tanımlanır ?
  • Arrow Fonksiyonun Sağladığı Ekstralar.

Fonksiyon Türleri

Aşağıda yaptığım sınıflandırmalar bana göre, yani tek bir sınıflandırma altında konuyu ele alamadığım için farklı bakış açıları içerisinde bu fonksiyon türlerini sınıflandırdım.

A. İsimlendirmelerine Göre Fonksiyon Türleri

Eğer bir fonksiyonun ismi var ise buna Regular/Named Functions deriz. Bu bizim bildiğimiz en basit fonksiyon tanımlama yöntemidir. Aşağıdaki örnekte topla isminde bir fonksiyon tanımladık. topla(3,5); herhangi bir yerden çağırdığımızda istediğimiz 2 değeri toplayıp sonucunu dönecektir.

function topla(a,b){return a+b;}

Eğer ki fonksiyonun bir ismi yok sadece referansını(pointer adresini) bir değişkene atıyorsak bu Anonymous Functions deriz. Burda ki fonksiyonun bir ismi yoktur sadece referans adresi vardır. topla(3,5); çalışacaktır. Bu sefer fonksiyonun referansını tutan bir değişken üzerinden işlemlerimizi yapabiliriz.

let topla=function(a,b){return a+b;}

B. İşlevlerine Göre Fonksiyon Türleri

Fonksiyon bir state tutmuyorsa dışarıdan aldığı değerleri işleyip geriye sonuç dönüyorsa bu tip fonksiyonlara Pure Functions deriz. Burda bir önemli hususta kendisine değer olarak geçirilen parametreleride değiştirmemesidir. Yani dışarıya oldukça izole bir şekilde hizmet vermesi gerekir. Aşağıdaki örnekte toplama işlemi sırasında a ve b değişkenlerinde bir değişiklik yapmıyor ve sadece bunları kullanarak bir sonuç üretip bu sonucu döndüğü için bu tip fonksiyonlar Pure Functions diyoruz.

function topla(a,b){return a+b;}

Biz fonksiyon ile bir nesne oluşturuyorsak. Bu tip fonksiyonlara Constructor Functions diyoruz. Örneğin aşağıdaki örnekte isim ve yaş değerlerini alarak istenilen kullanıcılardan oluşturulabilir.

let Kullanici=function(isim,yas){
this.isim=isim;
this.yas=yas;
}
const ali=new Kullanici('ali',12);

Eğer bir fonksiyon hemen çağrılıp oluşturulan sonuç/sonuç objesi bir değişkende saklanıyorsa bu tip fonksiyonlara IIFE (Immediately invoked function expression) deniyor. Bu tip fonksiyonların amacı genelde bu scope içerisinde oluşan değişkenlerin sadece o kapsam(scope) erişilebilir olmasını sağlıyor. Genelde JQuery, Prototype gibi kütüphanelerde değişken isimlerinin çakışmaması ve scope içerisinde işlemlerin yapılabilmesi için IIFE yöntemi kullanılmıştır. Daha sonra anlatacağım module kavramları ile birlikte ileride bu konu üzerinde daha detaylı duracağım.

const talkOnur= (function talk(name,text){
var konusan=’konusan’;
return konusan+'' + name+': '+text;
})(“Onur”, “Merhaba”);

Generators fonksiyonlarda ES ile gelen yeni fonksiyon türlerinden olduğu için bu konuya da daha sonra değineceğim.

Argümanlarında 1 yada 1 den fazla function referansını parametre olarak alan veya return değerini geriye fonksiyon olarak dönen fonksiyonlara High Order Functions denir. Çok yakından tanıdığımız Array sıkça kullandığımız aşağıdaki fonksiyonların hep bu türde fonksiyonlardır.

[].forEach (e=> …) //iterate every elements
[].find(e=>…) //return an element according to condition
[].findIndex(e=>…) //return an element index according condition
[].filter(e=>…) return items according to condition
[].sort(e=>…) sorts according to given condition
[].map(e=>…) transform existing array to other array
[].reduce(e=>…) combines elements and return an element
[].some(e=>…) check some elements
[].every(e=>…)

Birde return değeri olarak fonksiyon dönen bir örnek vermek istersek aşağıdaki popüler örneği verebiliriz. Ben bir 10 toplayıcısı oluşturmak istiyorum. Bu tip fonksiyon template oluşturmakte High Order Functions kullanabilirsiniz.

function makeAdder(x){
return function add(y){
return x+y;
}
}
const tenAdder=makeAdder(10);
console.log(tenAdder(12)); //22

C. İşleyiş Türlerine Göre Fonksiyon Türleri

Eskiden JS dünyası çok basitti. Arka arkaya senkron şekilde çalışan bir fonksiyon ile işlerimizi halledebiliyorduk aşağıdaki işlem Synchronous Functions türündedir. Tüm satırlar sıra ile işletilir.

function toplaVeYazdir(a,b){
const sum=a+b;
console.log(`Toplam:${sum}`);
}
toplaVeYazdir(3,4)

Ama bu fonksiyon türü tarayıcı ile sunucunun haberleşmesi sırasında yeterli olmayacaktır. Tarayıcı’dan sunucuya bir çok AJAX(haberleşme) isteği gidiyor ve bunların sonuçlarını senkron olarak beklersek kullanıcı tarayıcıda sürekli beklemek zorunda kalır. Biz bunun yerine async işlemler yapıyoruz işlem sırasında bir callback fonksiyon oluşturuyoruz. Bu callback fonksiyon AJAX request sonucunu bekliyor. Daha sonrasında ordan gelen response göre işleyen bir kod bloğu mevcut. Tabiki kod çok karmaşıklaşıyor ama son kullanıcıya çok güzel bir şekilde diğer işleri ile de uğraşmasına imkan olanak sağlıyor. Günümüzde bu sadece Tarayıcı sunucu arasındaki bir ilişki değil heryerde API’ler ve Servisler mevcut Örneğin bir AWS S3, DynamoDB servisi çağırırken de her işlem genelde async olarak gerçekleşiyor. Bundan dolayı bu tip işleyişe sahip fonksiyonlara Asynchronous Functions deniyor

function wait1SecAndSayHello(callback){
setTimeout(()=>{
console.log("Hello")
return callback({name:'onur'});
},1000);
}
function main(){
const result=wait1SecAndSayHello((result)=>{
console.log(result);
}
)main();

Yukarıdaki örnekteki bunun callback ile nasıl yapıldığını görebilirsiniz. Bu async fonksiyonların arka arkaya birbirine bağımlı olarak çağrıldığı durumlarda Callback Hell oluşur buda kodun okunmasını oldukça zorlaştırır bu durumu iyileştirmek için Promise, await, async kullanılmaktadır.

Son olarak Generator Functions’dan bahsetmek istiyorum. Normalde bir fonksiyon işlerken bu işlemin ortasında fonksiyonu durdurup tekrar başlatamayız. Bunu sağlayan yield sayesine artık buda mümkün. Birde Generator fonksiyonlar aynı işlem içerisinde tek bir değer değilde bir değer grubu dönebilirler.

function* generator(i) {
yield i;
yield i + 10;
}
var gen = generator(10);
console.log(gen.next().value);
// expected output: 10
console.log(gen.next().value);
// expected output: 20
Takes from MDN

Arrow Fonksiyonları Nasıl Tanımlanır ?

Arrow fonksiyon dediğimiz fonksiyon kodlarımızı daha matematiksel bir dille yazmak diyebiliriz.

sum=(a,b)=>a+b;

Aşağıda normal fonksiyonların arrow fonksiyonlar ile nasıl tanımlandığını anlatınca artık matematik fonksiyonu yazdığınızı düşüneceksiniz. Bu yazım şeklinin sizin hem kod yazmanızı kolaylaştırdığını hemde kod okunurluğunu arttırdığını farkedeceksiniz.

Farklı Arrow fonksiyon tanımlamalarına bakacak olursak aşağıdakilere örnek olarak verebilirim.

  • Hiç parametre almayan sabit fonksiyon
  • Parametre alıp cevabını dönen pure fonksiyon
  • Tek parametresi olduğu için parametre kapsülü() olmayan tanımlama
  • vb…
pi=()=>Math.PI; console.log(pi());
sum=(a,b)=> return a+b; console.log(sum(2,7));
square=x=>x*x; console.log(square(9))
f=(x)=>{const y=x+3; return (g=(t)=>t*(t+5))(y)}; console.log(f(2));

Peki kodu nasıl daha okunabilir hale getiriyor. Yukarıdaki Higher Order Fonksiyondan verirsek. Normal şekilde yazılan bir fonksiyon aşağıdaki gibi yazılırken

function makeAdder(x){
return function add(y){
return x+y;
}
}
const tenAdder=makeAdder(10);
console.log(tenAdder(12)); //22

Arrow Function yazılan aynı kodun ne kadar basit bir şekilde yazıldığını görebilirsiniz. İşte bu ES6 Arrow fonksiyonun gücü diyebiliriz.

makeAdder = (x) => (y) => x + y
const tenAdder = makeAdder(10);
console.log(tenAdder(12));

Arrow Fonksiyonun Sağladığı Ekstralar

Aşağıdaki kavramlar biraz karışık. Bu kavramları daha sonradan Derin JS konuları içerisinde anlatacağım. Burda sadece kısaca bahsetmek istedim.

Not 1: Arrow fonksiyonların constructor veya prototype yoktur. new ile birlikte kullanılmaz. Amacı bir object instance oluşturmak değildir.

Not:2 olarak arrow fonksiyonlar kendi this binding kendisi bağlamaz lexical scope context kendisini binding otomatik olarak yapar.

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara (JS Pratik Kullanımı) erişmek için bu linke tıklayabilirsiniz.

Bu yazının devamı veya yazı grubundaki diğer yazılara (JS Derinlemesine Öğren) erişmek için bu linke tıklayabilirsiniz.

--

--