Javascript ve Nesnel Programlama

Bu yaziyi bitmis bir makale degil de benim tuttugum notlardan olusan bir yazi olarak dusunmek daha dogru. O yuzden boluk bolcuk ve bitmemis durumda zamanla duzelte duzelte adam edecegim.

Baya bir suredir Javascript kullanirim ancak bu kullanim var olan JQuery pluginlerini dogru durust entegre etmek, gerekirse bir iki fonksiyon yazmaktan oteye gecmez. Son bir is var yapmam gereken ve pek oyle basit bir is degil adam akilli bir MVC yapisi kurmam, gerekli. Once Backbone.js kullanmayi denesem de, Backbone'un view katmaninin DOM elemanlarini manuple edecek sekilde hazirlanmis olmasi isi bozdu. Zira benim yapacagim is kullaniciya canvas uzerinde bir takim resimler cizdirmek.

Javascript ile Nesne Yonelimli Programlamaya dair tuttugum notlar su sekilde

Variable Scope (Degisken Kapsami)

Javascript degiskenlerin nerede gorunur nerede gorunmez olduguna function scope (fonksiyon kapsam) kullanarak karar veriyor. Yani her degisken kendi icinde bulundugu fonksiyon icerisinde gorunur durumda. Ancak ic ice gecmis fonksiyonlarda  icerideki bir degisken kullanildigi zaman once fonksiyon icerisinde, eger bulunamaz ise distaki fonksiyonda aratiliyor.

Asagidaki ornekte bir myvar adli bir degisken var, bu global bir deger en tepede duruyor. is_exists() fonksiyonu cagirildigi zaman once fonksiyon icerisinde araniyor, bulunamadigi icin bir uste yani global katmanina cikiliyor. Orada bulundugu icin myvar goruntuleyebiliyoruz.

var myvar = "here i am!";
function is_exists() { console.log(myvar); };
is_exists();
> here i am!

Global degisken gorulmuyor olsa da eger fonksiyonlari ic ice kullanir isek, alttaki fonksiyon usttekine ait degiskenleri gorebiliyor. Asagidaki ornekte outer fonksiyonunu cagiriyoruz, o da deger olarak kendi icindeki inner fonksiyonunu donduruyor. inner fonksiyonu outer'a ait myvar degerini getiriyor.

function outer()  {
    var myvar = "here i am!"
        function inner() {
            console.log(myvar);
        }
    return inner();
};
outer();
> "here i am!"

Fonksiyon Tanimlamalari

Javascript'te klasik fonksiyon tanimlamalari mumkun, bunun yaninda bir de anonim (isimsiz) fonksiyonlar var. Anonim fonksiyonlar genelde bir deger uzerine atanarak kullaniliyor ya da baska fonksiyonlara parametre olarak gonderiliyor. (evet biraz kafa karistirici olmaya basladi)

Asagidaki bir klasik fonksiyon olusturma ornegi:

function nameOfFunction(listOfVariableNames) {
    ...
    ...
}
var a = nameOfFunction();

Bu fonksiyonun yaptigi islemin sonucunu bir a degiskenine atadik. Eger istersek tekrar kullanabilir, baska bir degiskene de atayabiliriz.

Asagidaki ise isimsiz bir fonksiyon

b = function(listOfVariableNames) {
    ...
    ...
};

Burada fonksiyonumuzu b degiskenine atamis oluyoruz ancak atamayabilirdik. Bir fonksiyon digerine parametre olarak verildiginde kullaniliyor genelde bu ozellik.

Nesneler

Javascript her ne kadar kendini nesnel bir programlama dili olarak tanitsa da Javascript'de her sey nesne degil. Ilkel degerlere (undefined, null, boolean, string ve number) sahip. Ilginctir ki bu ilkel degerlere objeymis gibi davranir, her hangi bir metodunu cagirmaya kalkarsaniz; ilkel deger, nesneye dusuyor (fall back) ve metod cagiriliyor.

var a = "hi!" // bu bir string, yani ilkel deger
console.log(a.length); // burada fall back islemi gerceklesiyor, objeye donusuyor
> 3

Ikinci bir gariplik ise Javascript'de sinif kavraminin bulunmayisi. O_o

Ancak turetme islerini bir obje olusturup buna ait metodlari ve ozellikleri yine de baska objelere aktararak halledebiliyoruz.

Javascript'de bir obje olusturmanin en kisa yolu su sekilde:

var ninja = {
    name: 'Shadow Warrior'
    health: 100,
    swing_sword: function() {
        alert("swosh!");
    }
};
ninja.swing_sword();

ninja adinda bir obje olusturmus olduk. Icindeki swing_sword (kilic salla) metodunu kullandik. Ancak bunu olustururken dict nesnesini baz alarak olusturdugumuz icin her ne kadar bos bir nesne olusturduk gibi gozukse de dict objesinin metodlari ile birlikte gelmis oluyor.

Insa Edici Fonksiyonlar (Constructor Functions) ve New ifadesinin kullanimi.

Adindan da anlasilacagi uzer insa edici fonksiyonlar sizin nesneleri insa etmenizi saglayan fonksiyonlar oluyor. Bizim nesneleri dinamik bir bicimde insa edebilmemizi sagliyor. Ornegin bir kac ninja nesnesine ihtiyac duymus olalim ve bunlarin name ve health degerleri birbirinden farkli olsun. Bu durumda uzun uzun yazmak yerine asagidaki gibi bir yol izleyebiliriz.

function NinjaConstructor(name, health) {
    this.name = name; 
    this.health = health;
    this.swing_sword: function() {
        alert("swosh!");
    }
}
var ninja1 = new NinjaConstructor('mirat', 100);
var ninja2 = new NinjaConstructor('osman', 62);
console.log(ninja1.name, ninja1.health);
> mirat, 100
console.log(ninja2.name, ninja2.health);
> osman, 62

Burada new ifadesi dikkatinizi cekmistir, bu ifade al bu fonksiyondan obje uret demek icin kullaniliyor. new ifadesini kullanmasaydik atadiginiz degerler fonksiyonun kendisi olacakti.

Insa edici fonksiyonumuzu (NinjaConstructor) yazdiktan sonra aslinda fonksiyonun urettigi ozellik ve metodlari uretilen nesnelere aktardigimiz icin bir nebze miras alma-verme mevzusunu cozmus oluyoruz. Ancak yine de bazi durumlarda bu yeterli olmaya biliyor.

Miras Mevzusu (Prototypal Inheritance)

Javascript miras alma islerini nesnelerin icine yerlestirdigi prototype adindaki baska bir objeyi kullanarak hallediyor. Siz nesne icindeki bir ozelligi ya da metodu cagirdiginizda eger yok ise, prototipine bakiliyor, orada da yok ise undefined donduruyor. Soyle,

// bu a nesnesini, prototip olarak kullanacagim:
class a = {
    hello: function () {
        alert("hello!")
    },
}

// bu da miras alacak sahis:
class b = {
    bye: function () {
        alert("goodbye!")
    },
}

// su anda b nesnesi hello fonksiyonuna sahip degil
console.log(b.hello)
> undefined

// b nesnesinin prototipini a olarak belirliyorum
b.__proto__ = a

// hello fonksiyonunu cagirdigimda once b objesine bakilacak
// bulunamadigi icin prototipine gidilecek, oradaki metod calistirilacak.
b.hello()
> hello!

Bu arada yeri gelmisken hemen belirtmek gerekir ki new ifadesi ise aslinda yeni bir obje olustururken, ona verdiginiz insa edici fonksiyonun prototipine bakiyor.

06/2012