Javascript, bütün web tarayıcıları tarafından kullanılan bir dildir. Yani eğer web üzerinde programlama yapıyorsak bu dili öğrenmek bize inanılmaz avantaj sağlar. İşi gereği Ajax kullanma ihtiyacı hisseden herkes eninde sonunda bir şekilde Javascript'e bulaşmak zorunda kalır. Ancak diğer zamanlarda C#, Vb.Net, vbscript ya da coldfusion gibi diller kullanan yazılımcılar günün birinde -zorunluluktan- javascript kullanmaya niyetlendiğinde, çok iyi bildiği diğer dilden vaz geçip hiç araştırmaya vakit bulamadan javascript kullanmaya başlayınca ne yazık ki sonunda oradan buradan bulduğu kodları "güzelce" kopyala yapıştır yapıp çalışmasını beklerler. Elbette bu da sorunlara yol açtığı zaman sorunu "mülayim" javascript'te bulurlar. Evet, Javascript aslında oldukça mülayim bir dildir. Öyle ki, aslında javascript derleyicisi bize dert çıkartmamak için elinden geleni yapar. Örneğin, hepimizin bildiği gibi javascript komutları noktalı virgül (semicolon [;]) ile ayrılır. Diğer pek çok C türevi dilde bunu yerleştirmediğimizde derleyiciden hata alır komutumuzu derleyemeyiz. Ancak javascript derleyicisinde, her kod satırı çalışsın diye "semicolon correction" adında bir mekanizma yer alır. Bu mekanizma ile birlikte satır sonlarında eğer scope parantezi, ({ ya da }) yoksa derleyici otomatik olarak noktalı virgül işaretini yerleştirecektir. Tabi ki bu da çoğu zaman başımıza dert açabilir. Bu yüzden javascript ile kod yazarken en dikkat etmemiz gereken şey, herşeyi kuralına göre yapmış olmamızdır. örneğin,
return
{
degisken : true
}
gibi bir kod yazdığımızı düşünelim. Bu durumda derleyici üstteki kodu aşağıdaki gibi düzeltecektir,
return;
{
degisken : true;
}
yani böyle bir durumda geri dönüş değerinin bir nesne olmasını beklerken sürekli undefined sonucunu elde etmemiz çok da süpriz olmamalıdır. Bu kodun doğrusu aşağıdaki gibi yazılmalıdır,
return {
degisken: true;
};
Bu gibi sorunların yanında en çok problem "if" gibi mantıksal ifadelerde karşımıza çıkar. C ve türevi dillerden gelen alışkanlıkla mantıksal eşitlik için daima "=="(eqeq) kullanmaya alışmış bir yazılımcı javascript için de aynısını kullanır. Ancak burada diğer dillerden farklı olarak, javascript derleyicisi eqeq operatörünü kullanırken tipler arasında sıkıntı yaşamamak için tip dönüşümü yapar. Yani bu durumda aşağıdaki sorunlar karşımıza çıkabilir,
alert('\r\n\t' == 0); // true
alert(false == '0'); // true
alert(0 == '0'); // true
alert('' == 0); // true
alert(undefined == null); // true
Ancak javascript bu durumun bir çözümünü de bizlere sunmaktadır. Bu sorunla karşılaşmamak için "==="(eqeqeq) operatörünü kullanabiliyoruz. yani (false === '0') ifadesi bize false değerini döndürüyor. Çünkü ifadenin bir yanında boolean bir değer varken diğer tarafta ise bir string değeri yer alıyor. Benzer şekilde bir başka problem ise, değeri verilmemiş bir değişkenin değerinin ne olacağıdır. Bu undefined ya da null olabilir. Bunun içinse çoğu zaman
if(degisken != null || degisken != undefined || degisken != 'undefined') { .. }
yazmak zorunda kalabiliriz. Bunun bir çözümü de basitçe değişkeni mantıksal yolla sınamaktır,
if(degisken){...}
Bu şekilde yazdığımızda bir ifadede javascript derleyicisi, if mantıksal sınamasında öncelikle degisken'in değerine bakar, eğer bu değer dolu ise true, değil ise false değerini döndürür.
Javascript number, string, boolean, null ve undefined gibi tiplerden oluşur. Yani diğer dillerde gördüğümüz kadar çok tip yer almaz. Bunun dışındaki tüm tipler birer object tir. Tanımlanmamış her object undefined ya da null değerini alır. Eğer bu değerlere sahip olmayan bir nesne yaratmak istiyorsak bunu aşağıdaki gibi yapabiliriz,
var bos_nesne = {};
Yukarıdaki tanımda yer alan nesnenin değeri object olarak gelecektir. Bu nesnenin içerisine özellikler eklememiz de mümkün,
var yeni_nesne = {
ozellik1 : 'string değer',
ozellik2 : 12,
ozellik3 : true,
fonksiyon : function(x){
return x * 2;
}
};
Yukarıdaki örnekte de görüldüğü gibi bir nesnenin özellikleri değişken tipleri olarak verilebileceği gibi birer fonksiyon olarak da tanımlanabiliyor. Böyle bir yaklaşımla gayet nesneye yönelik bir tasarıma da izin verilmektedir. Benzer şekilde bir nesneye yapıcı method da tanımlamak mümkündür,
var nokta = function(x, y){
this._x = x;
this._y = y;
};
Javascript nesnelerinin (javascript 1.1'den itibaren) her birinde prototype adında bir özellik bulunur. Biraz ciddi bakıldığında bu prototype özelliğinin, javascript nesnelerinin nesneye yönelik programlamaya açılan kapıları gibi olduğu söylenebilir. Bir nesneye ait prototype özelliğine eklediğiniz her yeni fonksiyon ya da özellik o nesnenin tüm kopyaları için geçerli olur. Yani bir nesnenin prototype özelliğini kopyaladığınızda o nesneye ait tüm özellik ve fonksiyonları da miras almış olursunuz. Bu şekilde çok daha karmaşık sistemleri kısa ve etkili bir şekilde tasarlayabilir, nesneye yönelik tasarım kalıplarını javascript ile uygulama şansını elde edebilirsiniz. Şimdi aşağıda, üstte tanımladığımız nokta nesnesine yeni bir fonksiyon ekleyelim,
nokta.prototype.MesajGoster = function(){
alert(this._x + ':' + this._y);
};
Böylece aşağıdaki gibi bir kullanımı rahatlıkla yapabiliriz,
var yeni_nokta = new nokta(10,12);
nokta.MesajGoster();
Bu tanımla birlikte, nokta nesnesini miras alan bir baska nesne de MesajGoster fonksiyonundan faydalanabilir. Şimdi yeni bir nokta nesnesi yapalım ve bu nesne daha once yaptığımız nokta nesnesinin MesajGoster ozelligini miras alsın,
var altNokta = function(x, y){
this._x = x * 2;
this._y = y * 2;
};
altNokta.prototype = nokta.prototype;
var alt_nokta = new altNokta(1,2);
alt_nokta.MesajGoster();
Yukarıdaki örneği de uyguladığımız zaman, aslında altNokta nesnesine MesajGoster() fonksiyonunu tanımlamamış olmamıza rağmen, bu fonksiyonun çalıştığını görebilirsiniz. Peki şimdi burada bir problemimiz daha var. Farkındaysanız yapıcı metodlar arasında kodu tekrarlamak durumunda kaldık. Şimdi de hem bunu engelleyelim, hem de miras alma olayını ortak bir yapıya çekelim. Bunun bu tarz işlemlerde bize kolaylık sağlayacak aşağıdaki fonksiyonu kullanabiliriz,
var inherits = function(subObject, baseObject){
subObject.prototype["base"] = baseObject;
for (var subPrototype in baseObject.prototype) {
if(subPrototype !== "base"){
subObject.prototype[subPrototype] = baseObject.prototype[subPrototype];
}
}
}
Öncelikle yukarıda ne yaptığımızı biraz anlamaya çalışalım. İlk başta miras alacak olan nesnenin prototipine base isminde yeni bir özellik ekledik. Bu şu demek, artık miras alacak olan subObject nesnesinin miras aldığı nesne değerine sahip bir özelliği var. Yani kendi içerisinde this.base dediğimizde ya da dışarıdan nesneAdi.base dediğimizde o nesnenin ust sınıfına erişebiliyoruz. Üstte yaptığımız örneği bu yapıda tekrar edelim,
var altNokta = function(x, y){
this.base(x * 2, y * 2);
};
inherits(altNokta, nokta);
Sanırım bu şekilde nesneye yönelik diğer dillere daha yakın bir kullanım elde edebildik. Javascript ile temel düzeyde miras alma işlemini öğrendiğimize göre son bir örnek yapalım. Şimdi yapacağımız örnekte aynı tipten türemiş iki tane nesneden tipine göre bizim ihtiyacımızı döndüren bir fabrika methodu hazırlayalım. Aynı Urunler nesnesinden türeyen iki nesnemiz olsun, biri Kalemler diğeri ise Kitaplar. öncelikle Urunler nesnesini tasarlayalim,
var Urunler = function(urunTipi, urunAdi){
this._urunTipi = urunTipi;
this._urunAdi = urunAdi;
};
Urunler.prototype.Yukle = function(){
alert("Urun tipi " + this._urunTipi + " olan " + this._urunAdi + " yuklendi.");
};
Ardından bu nesneyi miras almış olan Kalemler ve Kitaplar nesnelerini tasarlayalım.
var Kalemler = function(urunAdi){
this.base("kalem", urunAdi);
};
inherits(Kalemler, Urunler);
var Kitaplar = function(urunAdi){
this.base("kitap", urunAdi);
};
inherits(Kitaplar, Urunler);
Şimdi de bu iki nesneyi yaratıcak olan UrunFabrikasi'ni tasarlayalim,
var UrunFabrikasi = {
UrunYarat : function(urunTipi, urunAdi){
switch(urunTipi){
case "kitap":
return new Kitaplar(urunAdi);
break;
case "kalem":
return new Kalemler(urunAdi);
break;
}
}
};
Artık örneğimizi bitirdik, buradaki yapıyı aşağıdaki gibi kullanabiliriz,
var urun = UrunFabrikasi.UrunYarat("kalem", "Yeni bir kalem");
urun.Yukle();
Daha anlatılacak çok şey olmasına rağmen burada ara veriyorum. Bu yazıya başlarken amaçladığım şey, her ne kadar yazılım dilleri değişse de ortak yöntemlerin ya da methodların bir şekilde adapte edilebileceğini ve javascript'in de doğru kullanıldığında neler başarabileceğini göstermekti. Umarım artık sizin de javascript'e bakış açınız bu yazıyı okumadan önceki gibi değildir. Görüşmek üzere.