Nis
25
2011

JavaScript’e Hızlı Giriş – Bölüm 2

Önceki yazımızda JavaScript’in ilginç nesne yapısına şöyle bir göz atmış, hatta bir kaç basit örnek bile yapmıştık. JavaScript’in prototip temelli sınıflarına ve daha önemlisi “fonksiyonel” yapısına daha fazla eğilmenin vakti geldi.

JavaScript Wikipedia’daki tanımında da görebileceğiniz üzere aynı zamanda fonksiyonel bir dildir. Buradaki “fonksiyonel” kavramını yüzeysel olarak “fonksiyon temelli” diye açıklarsak çok da yanlış yapmış sayılmayız sanıyorum. Fonksiyonel bir dilde fonksiyonlar da temel sınıflar arasındadır. Yani bir fonksiyon ile alelade bir nesne arasında kullanım yerleri açısından bir fark yoktur:

  1. Bir fonksiyona parametre olarak verilebilirler
  2. Bir fonksiyondan geriye sonuç olarak döndürülebilirler
  3. Bir fonksiyon içerisinde tanımlanıp, değişkene atanabilirler

JavaScript’te tüm tipler özünde nesne olduğu için, fonksiyonlar da bir nesnedir. Bir önceki yazıdaki kodu dikkatli incelerseniz tanımladığımız fonksiyonun “prototype” adlı özelliğine erişerek bu durumu aslında hem gösterdik hem de kullandık. JavaScript’in nesneler konusundaki esnekliğini fonksiyonların nesne olması durumu ile birleştirdiğinizde çok ilginç şeyler yapmak mümkün. Örneğin özyinelemeli(recursive) bir faktöriyel fonksiyonu yazıp, hesapladığımız değerleri fonksiyonun bir alt özelliğinde saklayarak sonraki erişimleri hızlandırabiliriz. Örneğimiz gelsin hemen:

window.faktoriyel = function faktoriyel(n) {
  var sonuclar = faktoriyel.sonuclar;
  var sonuc = sonuclar[n];

  if (sonuc)
    return sonuc;
  else
    return sonuclar[n] = faktoriyel(n - 1) * n;
};
faktoriyel.sonuclar = {0: 1, 1: 1};

Örneğimizi adım adım inceleyelim:

  1. Öncelikle fonksiyonumuzun “sonuclar” elemanına erişip bunu “sonuclar” adlı yerel değişkene atıyoruz ki her seferinde faktoriyel.sonuclar yazmayalım uzun uzun. İleride göreceğimiz gibi bu şekildeki kullanımın performansa da olumlu etkisi var.
  2. Daha sonra “sonuc” adlı değişkenimize sonuclar nesnesinin “n” isimli değerini atıyoruz.
  3. Daha önce bahsettiğimiz gibi eğer sonuclar nesnesinde “n” isimli bir değişken yoksa “sonuc” değişkenimizin değeri “undefined” olacak.
  4. “if (sonuc)” ifadesi ile eğer “sonuc” değişkenimizdeki değer “undefined” değilse doğrudan önceden hesaplanmış sonucu geri dönüyoruz. Burada dikkat etmemiz gereken ufak bir nokta[1] var ancak konuyu dağıtmamak üzere bunu yazının sonuna saklıyorum.
  5. Eğer sonucumuz yoksa bize verilen sayının bir eksiğinin faktöriyelini alıp sayıyla çarpıyoruz. Elde ettiğimiz değeri ileride tekrar hesaplamamak için “sonuclar” nesnesinde saklıyor ve geri dönüyoruz.
  6. En can alıcı noktalardan bir tanesi aslında son satırda saklı. Burada hem “sonuclar” adlı nesnemizi tanımlıyoruz hem de özyinelemeli işlevimizde “durma noktası”nı sağlayacak başlangıç değerlerini veriyoruz: 0 ve 1′in faktöriyeli 1′dir.

Aslında bir kaç şeye daha değinmek istiyordum ancak yine yazı haddinden fazla uzadı. Bir sonraki yazıda geri-dönüş fonksiyonları(callback) ve JavaScript’teki olay tabanlı programlama mantığına girip, yerimiz yeterse kısa ve basit bir AJAX kodunu inceleyeceğiz.

[1] JavaScript’te otomatik tip dönüşümü(duck-typing) vardır. undefined, 0, false, boş metin(”) ve null değerleri if ifadelerinde kullanıldığında “false”, yani olumsuz olarak değerlendirilirler. Bu noktada sayısal bir değer olmasını beklediğimiz “sonuc” değişkeni içerisindeki değer 0 olursa elimizde bir değer olmasına rağmen kodumuz sanki yokmuş gibi davranacak. Ancak söz konusu işlev faktöriyel olunca, sonucun 0 olması gibi bir durum söz konusu olmayacağından bu şekilde kullanmamızda bir sakınca yok.

Yorum yapabilirsiniz..

  • Yazı güzel ancak uzun olmuş. Örnek biraz zayıf kalmış.

    Global scopeda function faktoriyel(n) referansına window.faktoriyel olarak zaten erişilebilir. Bu şekilde referansı tekrar aktarmak için bir sebep olması gerektiğini düşünüyorum. Mesela inner scope yaratmak gibi.

    Function’un bir Object türevi olduğunu belirtmek için daha etkili yollar kullanılabilir mesela:

    function getTypeName(obj) { return Object.prototype.toString.call(obj) }

    console.log(getTypeName(function(){}); // [object Function]
    console.log(new Function()); // [object Function]

    • Tuğrul Bey,

      Öncelikle eleştirileriniz için çok teşekkür ederim. İlk ciddi yazı denemelerim olduğu için aksak yönler oluyor elbette. Eleştirilerinizin tamamını yeni yazı için dikkate alacağım.

      “Global scopeda function faktoriyel(n) referansına window.faktoriyel olarak zaten erişilebilir. Bu şekilde referansı tekrar aktarmak için bir sebep olması gerektiğini düşünüyorum. Mesela inner scope yaratmak gibi.”

      Bunun özel bir sebebi var, siz üzerine basınca belirtmek istedim. Burada isimlendirilmiş fonksiyon kullanmamın sebebi okuyanları bu duruma alıştırmak çünkü özyinelemeli(recursive) işlev yazarken işlevin kendisine erişmek için en temiz ve tavsiye edilen yöntem işleve isim verip bu ismi kullanmak. Bu işlevi farklı bir bağlamda/modülde de yazıyor olabilirdik sonuçta, bunu göz önüne alarak değerlendirirseniz bana hak vereceğinizi düşünüyorum.

      Tekrar teşekkürler =)

  • düzeltme:

    console.log(getTypeName(new Function())); // [object Function]

En son haber ve ücretsiz eğitimlere ulaşmak için üye olabilirsiniz