JavaScript Temelleri

Bölüm 2

Temel Bilgiler

2.5 - Fonksiyonlarla Çalışmak

Bölüm 2 Sayfa 5

2.5.1 - Fonksiyonların Tanıtımı, Fonksiyon İsim Uzayı

Fonksiyonlar, ana programdan bağımsız olarak kod çalıştırabilen alt programlardır. Fonksiyon gövdesi olarak adlandırılan, fonksiyon kod çalıştırma alanında, ayrı bir program alanı olarak, aynen ana program alanı gibi, fakat ana program alanından bağımsız olarak program adımları çalıştırılır ve sonuçlar ana program alanına aktarılabilir. Fonksiyonlar tanımlandıkları anda çalıştırılmazlar, Bir dış program adımından veya kendi içinden (rekürsif fonksiyonlar) çağrılarak çalışabilirler.

Fonksiyonlar, programların gerçek yapıtaşlarıdır. Çünkü, modern tasarım kavramına göre, programlar fonksiyonların içinde çalıştırılır, ana program sadece çesiştli fonksiyonlar aralarında bilgi alışverişini koordine eder.

Bilgisayar programlamasında kullanılan fonksiyonlar, 1930 larda geliştirilen lambda kuramından (λ-cebri) geniş ölçüde etkilenmiştir. λ Kuramı modern program dilerinde, fonksiyonların λ kuramı kurallarına uygun olarak tasarlanmasına yol açmıştır. Bu konuda, Scheme, ML, Haskell, Lisp (özellikle Pure Lisp), Pascal, Python gibi modern programlama dilleri örnek olarak verilebilir. Javascript programlama dili de, fonksiyonları λ kuramına en yakın olarak tasarlanmış olan az sayıda programlama dilinden biridir.

JavaScript programlama dilininin üstün yönlerinden birisi, fonksiyonlarının λ kuramına tam uyumlu olarak tasarlanmış olmaları ve bunun sonucu olarak, fonksiyonlarının birinci sınıf nesneler olmasıdır. 1960 larda Christopher Strachey tarafından tanımlanmış olan birinci sınıf nesneler,

JavaScript fonksiyonları, birinci sınıf nesneler olarak yerleştirilmişlerdir. Olayın öneminin vurgulanması için bunun nekadar zor olduğunu ve ne kadar az programlama dilinde bu olanağın sağlanmış olduğunu belirtmek yeterli olacaktır. JavaScript fonksiyonlarının, birinci sınıf nesneler olarak yerleştirilebilmiş olması, Javascript programlama diline uygulamada büyük esneklik ve uygulama özgürlüğü sağlamaktadır.

Javascript programlama dilinde, fonksiyonlar, JavaScript yorumlayıcısına üç türlü tanıtılabilirler. Bunlar,

olarak sayılabilir.

Bunlardan ilki, yani function bildirimi JavaScript programlama dili için temel fonksiyon tanımlama yöntemidir. Bu yöntemle bildirilen fonksiyonlar sadece bir kez çözümlenirler ve program belleğine yerleşirler. Bu yöntemle tanıtılmış fonksiyonlar, gerçek alt programlar olarak görev yaparlar. İkinci yöntem, fonksiyon literalleri olarak tanımlanan bir yöntedir Bu yöntem daha az kullanılır ve çoğunlukla bir tek defa kullanılacak ve isimlendirilmesi gerekli olmayan, ve bir ifade gibi tanıımlanan bir fonksiyon türüdür. Fonksiyon literalleri de tanımlandıktan sonra bir kez çözümlenirler. Fonksiyon nesneleri, bölüm7 de açıklanacağı gibi, öntanımlı Function() nesne yapılandıcı fonksiyonunda yararlanılarak yaratılan Function nesne sınıfı örnekleridir. Fonksiyon nesnelerinin yazılımları alışılmamaış olduğundan ve her çağrıldıklarında yeniden çözümlenmek zorunda olduklarından dolayı performans kaybı yarattıklarından ve işlevleri zaten fonksiyon literalleri tarafından yerine getirildiğinden, kullanım alanları hiç yok gibidir.

Burada sadece genel fonksiyon bildirimi ve fonksiyon literalleri incelenecektir. Fonksiyon nesneleri, bölüm 7 de Function nesne sınıfı ile birlikte incelenecektir.

2.5.2 - function Bildirimi

Fonksiyonların en genel tanıtımları, fonksiyon bildirimi kullanılarak yapılır. function bildirimi, ECMA-262 de bildirimler (statements) arasına alınmamıştır. Microsoft JScript spesifikasyonda ise bildirimler arasında görülmektedir. İşlevi açısından bildirimlere daha yakın olan, function bildirimini biz de bildirimler arasında inceleyeceğiz. Aslında isterse ECMA-262 spesifikasyonun öngördüğü gibi, bağımsız bir saklı sözcük olsun, isterse Microsoft JScript spesifikasyonda öngörüldüğü gibi, bir bildirim olarak kabul edilsin, function bildiriminin işlevi değişmemektedir. function Bildirimi ile JavaScript yorumlayıcısına tanıtılan bir fonksiyon, Function nesne sınfının yeni bir örneği olarak kabul edilir. function Bildirimi kullanılarak yapılan genel function tanıtımı,

function fonksiyonAdı([argüman1 [, ...[, argümanN]]]) {fonksiyon gövdesi}
		

şeklindedir. Burada,

fonksiyonAdı : (Gerekli) Yeni oluşturulacak fonksiyonun adı.

argüman1..argümanN : (İsteğe Bağlı) Fonksiyonun kabul edeceği argümanların listesi. Bir fonksiyonun alabileceği argüman sayısı 255 dir.

fonksiyon gövdesi : Fonksiyon çağrıldığında, çalıştırılacak program adımları (eğer sadece bir tek program adımı varsa, gruplama işlemcisine (parantezlere) gerek kalmayabilir. Fakat, bir konvansiyon olarak, her fonksiyon, mutlaka gruplama işlemcisi ile birlikte belirtilir.

Bu tanımdan, fonksiyon bildirimlerinde, fonksiyonların, tanımlayıcı (identifier) kısıtlarını karşılayacak bir ad ile tanıtılmaları gerektiği, isteğe bağlı olarak argümanlar alabildikleri isteğe bağlı olarak gövdelerinin olabileceği anlaşılır. Gövdesi olmayan bir fonksiyon, bir işlev de yapamayacağı için, bir amaç için oluşturulmuş fonksiyonların, mutlaka bir gövdelerinin olması gerekir.

function Bildirimi kullanılarak yapılan genel function tanıtımı, fonksiyonlar için esas tanıtım yöntemidir. Fonksiyon olarak tanıtılmış bir fonksiyon, tanıtıldıktan sonra, programcının envanterine geçer ve program kitaplığının ilişkilendirildiği her programda kullanılabilir. Bunun dışındaki tanıtım metotları, bu genelleşmeyi sağlamaz.

Her fonksiyon, bir Function nesne sınıfı örneğidir. Bu nesne sınfının tüm özelliklerine sahiptir. Bu özellikleri ileride, Function nesne sınıfının incelendiği bölüm 7 de göreceğiz.

Fonksiyonlarda this sözcüğü, fonksiyonu değil çağıran kapsamı işaret eder. Bu nedenle fonksiyonları kendi gövdeleri dahil her yerden kendi isimleri ile çağırmak gerekir.

function Bildirimi ile tanıtılan fonksiyonlar, tanıtılmadan önce de çağrılabilirler. Fakat bu sağlık verilmez. JavaScript programlama dili iyi yazım konvansiyonları, fonksiyonların önce tanıtılmaları sonra çağrılmalarını öngörür.

function Bildirimi ile tanıtılan fonksiyonların tanıtılmaları ile beraber, fonksiyonun adını ile aynı adla bir değişken yaratılır. Bu değişken adından, fonksiyonların başka değişkenlere atanmasında yararlanılır.

JavaScript fonksiyonları birinci sınıf nesneler olarak düzenlenmiştir. Fonksiyonlar değişkenlere atanabilirler. Fakat fonksiyonlar nesne niteliğindedir ve değişkenlere, kopyaları değil referansları aktarılır. Atamalar, referans aktarımı olduğundan, aynı atama işlemleri gibi, fonksiyon çağırma işlemcisi () kullanılmadan yapılır. Aşağıda JavaScript kodları verilmiş olan uygulamada bu yöntem açıklanmaktadır:

...

function ekle(a, b) {
			
return a + ' ' + b;
}

function çalıştırFonksiyon() {
			
var x = null, sözelVeri1 = 'Neşeli', sözelVeri2 = 'Günler', sonuç = null;
			
x = ekle;
			
sonuç = x(sözelVeri1, sözelVeri2);
			
sonuçVeTipYaz('x = ', x, 'b2.5.2-uyg-1-sonuç-1');
			
sonuçVeTipYaz('sonuç = ', sonuç, 'b2.5.2-uyg-1-sonuç-2');
}
...
		

Program Sonucu :

Bu uygulamanın sonuçları çok önemlidir. İlk olarak, burada x = ekle; ifadesi, ekle değişkenindeki fonksiyon referansının kopyasını x 'e ata anlamına gelmektedir. Bu atamadan sonra x değişkeni, ekle değişkeni gibi, isminin yanına bir fonksiyon çağırma operatörü eklenerek, aynı ekle değişkeni gibi fonksiyonu çağırabilir hale gelmektedir. Sonuç da x(sözelVeri1, sözelVeri2) şeklinde, yeni değişkenin fonksiyonu çağırması ile oluşturulmuştur.

Bu uygulamanın ikinci sonucu, fonksiyonun veri tipinin yeni bir veri tipi olan function tipinde olmasıdır. JavaScript programlama dilinde, veri tipleri, undefined, null, boolean, number, string, object ve function veri tipleridir. Yani, fonksiyonlar özel bir veri tipidir.

JavaScript programlama dilinde, her fonksiyonu yapılandırıcı bir fonksiyon (constructor) olabileceği düşünülerek her tanımlanan fonksiyona bir prototype özelliği verilir. Bu son derece sıradışı bir olaydır, çünkü Function nesne sınıfından başka hiçbir nesne sınıfının örneklerinin prototype özelliği yoktur. Başka nesne sınıflarının örnekleri, kendi sınıflarının prototipine sahip olurlar. Nesnelerin prototype özellikleri, Object nesne sınıfı ile birlikte incelenecektir.

Her fonksiyon tanımında, o fonksiyona ait bir argüman nesnesi de oluşturulur. Argüman nesnesi bir dizi nesnesine benzer, dizinin elemanları formal parametre listesindeki argümanlara karşı gelir. Bu nesnenin kullanımı, Array nesne sınıfı ile birlikte incelenecektir. Bu nesnenin kullanılmasını doğrulayacak bir uygulama yoktur. Her fonksiyon zaten formal parametre listesi ile tanımlanabilmekte ve aynı parametrelerle de çağrılabilmektedir.

function Bildirimi ile oluşturulmuş fonksiyonlar sadece bir kez çözümlenir ve istendiği kadar çağrılabilir. Bu şekilde, her çağrılışta yeniden çözümlenen fonksiyon nesnelerine oranla önemli bir peformans kazancı sağlanmaktadır.

function Bildirimi ile oluşturulmuş fonksiyonlar, mevcut çalıştırma kapsamının sonuna yeni bir kapsam alanı oluşturacak şekilde eklenir. Bu tür bir eklenmeye, kapsam zincirine yeni bir halka eklenmesi olarak nitlendirilir. Bu yeni kapsam alanı, bir üst kapsam alanınından ayrı ve bağımsızdır. Fakat, bir üst kapsam alanından bilgi alabilir ve bilgi verebilir.

2.5.3 - Fonksiyon Literalleri

Javascript programlama dilinde fonksiyonların gerçek λ olmalarının sonucu olarak birinci sınıf nesne niteliğinde olmaları, fonksiyonların, 2.5.2 paragrafında belirtildiği gibi çalışma anında (runtime) yapılandırılabilmeleridir. Fonksiyon literalleri bu özellikten yararlanmaktadırlar.

Fonksion literalleri iki türlü tanıtılabilirler. Bunlardan ilki aşağıda görülebileceği gibi, isimsiz fonksiyon literalleri olarak tanıtma yöntemidir. İsimsiz fonksiyon literalleri, anonim (klasik grekçe Sanskrit kökenli) fonksiyonlar olarak da adlandırılırlar. Anonim fonksiyonlar,

var değişken İsmi = function([argüman1 [, ...[, argümanN]]]) {fonksiyon gövdesi};
		

olarak tanımlanırlar. Anonim fonksiyonlara bir örnek olarak, JavaScript kodları aşağıda görülen bir uygulama verilmiştir.

...
var toplam = function (a, b) {
return (a + b).toFixed(3);
};

bilgiYaz(toplam(12.67, 190.789), 'b2.5.3-uyg-1-sonuç-1');
...
		

Sonuç :

Yukarıda görülen uygulamanın kodlarında, fonksiyon literalinin tanımından sonra, ifade sonlandırıcısı ; konulduğuna dikkat edilmelidir. Bunun nedeni, fonksiyon literali tanımının bir ifade olmasıdır. Bu nedenle, fonksiyon literalleri, fonksiyon ifadeleri olarak da adlandırılır. Yine yukarıdaki uygulamanın kodlarında görülen, toFixed() metodu, sayıların ondalık değerlerinin biçimlendirilmesi için sağlanmış bir sayısal nesne örneği öntanımlı metodudur.

Fonksiyon literallerinin ikinci tür tanıtımı, isimli fonksiyon literalleri olarak tanıtımdır. İsimli fonksiyon literallerinde tanımlanan fonksiyonun bir ismi olduğu için, anonim olarak nitelendirilemezler. Bir fonksiyon literaline isim verilmesi sadece fonksiyonların kendi kendini çağırması (rekürsiyon) yötemleri için gerekli olacaktır. İsimli fonksiyon literallerinin tanıtımı,

var değişken İsmi = function fonksiyonAdı([argüman1 [, ...[, argümanN]]]) {fonksiyon gövdesi};
		

şeklinde yapılır. İsimli fonksyon literallerine bir örnek olarak, kodları aşağıda görülen, uygulama verilmiştir.

...

var çarpma = function çarpım (a, b) {
return (a * b).toFixed(3);
};

bilgiYaz(çarpma(172.26, 5.86), 'b2.5.3-uyg-2-sonuç-1');
...
		

Sonuç :

Fonksiyon literalleri, aynı fonksiyon bildirimi ile tanımlanmış fonksiyonlar gibi tanımlandıktan sonra sadece bir kez çözümlenirler (parse) ve atandıkları kapsam alanında atandıkları değişken aracılığı ile çağrılabilirler. Yani gerek fonksiyon literallerinin, gerekse fonksiyon bildirimi ile tanımlanmış fonksiyonlar, performans kaybına neden olmazlar. Fonksiyon nesnelerinin ise, her çağrılışta yeniden çözümlenmeleri gerektiğinden özellikle döngü içlerinde, performans kaybına neden olurlar.

Fonksiyon literalleri, aynı fonksiyon bildirimi ile tanımlanmış fonksiyonlar gibi, tanımlandıkları kapsam alanını kalıtımla kazanırlar ve bu nedenle, biraz sonra inceleyeceğimiz kapalı devreler yaratabilirler. Fonksiyon nesneleri ise, sadece global kapsam alanını kalıtımla kazanabilirler ve bu yüzden kapalı devreler yaratamazlar.

JavaScript programlama dilinde temel fonksiyon tanımlama yöntemi, genel fonksiyon bildirimidir. Genel fonksiyon bildirimi ile tanımlanan bir fonksiyon, programın envanterine geçer ve ve programın her tarafından bir sınırlama olmaksızın çağrılabilir. Buna karşın, fonksiyon literalleri erişilebilirlikleri sadece atandıkları değişkenin kapsam alanı ile sınırlıdır. Bu açıdan, fonksiyon literallerinin kullanımları daha azdır ve sadece özel durumlarla kısıtlıdır. Genel fonksiyon bildiriminin yeterli olacağı işlevler için, fonksiyon literallerinin kullanımı anlamsız olacaktır.

2.5.4 - return Bildirimi

Fonksiyon isim uzayı, aynen global isim uzayı gibi her türlü kodu bağımsız olarak çalıştırılabilir. Bu bir bağımsız kod çalıştırma alanıdır ve global çalıştırma alanından izoledir. Fonksiyon alanında alınan sonuçlar istenirse global çalıştırma alanına (üst düzey programlama alanına döndürülebilr. Bunun için kullanılabilen return bildirimi, fonksiyonun program adımlarını çalıştırmasını keser ve argümanı olan ifade sonucunu fonksiyonu çağıran kod çalıştırma alanına döndürür. return Bildiriminin söz yazımı,

return [(][ifade][)]; 
		

şeklindedir. Gruplama işlemcisinin (parantez) kullanımı isteğe bağlıdır fakat konvansiyonel olarak kullanımı yapılmamaktadır.

Bölüm 1.6.2 de incelenmiş olan yapısal programlama prensiplerine göre, fonksiyonlara tek noktadan giriş, tek noktadan çıkış sağlanmalıdır. Javascript programlama dili, von Neumann yapılanmasına tam olarak uyum sağlamış bir yapılanma ile tasarlanmıştır. Bu nedenle, her fonksiyonda sadece bir tek return bildiriminin değer döndürmesi gözetilir.

2.5.5 - İçiçe Yuvalanmış Fonksiyonlar- Kapalı Devreler

Bir fonksiyon başka bir fonksiyon içinde tanımlanırsa bir kapalı devre (closure) oluşur. Kapalı devreler, JavaScript programlama dilinin en üstün yönlerinden biridir. Java gibi programlama dillerinde, bir fonksiyon geri dönüşü gerçekleştirdiğinde, ilgili program hafıza bölgesi (stack frame) , alt programın tüm değişkenleri ile birlikte ortadan kalkar. JavaScript'te ise, tamamen ortadan kalkmaz ve iç fonksiyon dış fonksiyonun değişkenlerine erişebilir.

Kapalı devreler, anlaşılması ve uygulanması zor olan ileri düzey konulardır. Tam olarak tanımı üzerinde dahi henüz fikir birliğine varılamamıştır. En güncel açıklama, bu konunun fonksiyonlarla değil değişkenlerle ilgili olduğudur. Bir sistem tüm değişkenlerine bir değere bağlayabiliyorsa (bind) bu sistem kapalı (closed) eğer dış değere gereksinme duyan serbest (sistem içinden bir değere bağlanamayan), değişkenler varsa, bu sistem, açık (open) bir sistemdir ve serbest değişekenini bağlayabilecek bir sistemle kapanmaya (closure) yatkındır. Böyle bir sistem çoğunlukla bir fonksiyondur.

JavaScript fonksiyonları, üstün statik veya sözlüksel (lexical) olarak adlandırılan kapsam alanına sahiptir. Ayrıca JavaScript fonksiyonları, parçalanamaz (immutable) niteliktedir. Bu niteliklerinden dolayı, fonksiyon tanımında tanımlanan tüm içerik, kullanımda kaldığı kadar yani tüm fonksiyonun çalışması tamamlanana kadar program belleğinin belirli bir bölgesinde kalır. Fonksiyon içeriği parçalanamaz olduğundan, İç fonksiyonun kullandığı dış değişken değeri kopyalanmaz ve tüm fonksiyon içeriği referansla aktarılır. Bu nedenle en son güncellenmiş dış fonksiyon değişkeni değeri iç fonksiyona aktarılır. Dış fonksiyonun çalışması tamamlanınca, iç fonksiyonun çağrısı devam ettiğinden dış fonksiyon içeriği bellekte kalmaya devam eder. Dış fonksiyon her çağrılışta, program belleğinde kapalı devrenin işgal ettiği eski alan kalır ve yeni bir kapalı alan bölgesi oluşturulur. Kapalı devrenin işgal ettiği program bellek alanları, JavaScript çöp toplayıcısı tarafından boşaltılmaya çalışılır. Bu yüzden, çok tekrarlı iteratif sistemlerde, kapalı devre uygulaması, çöp toplayıcısının yetersiz çalışması sonucunda program belleğini aşırı doldurabilir.

Sadece tanımlandıkları kapsamı içerebilen fonksiyon bildirimleri ve fonksiyon ifadeleri ile oluşan fonksiyonlar kapalı devreler oluşturabilir. Bu konuda bir uygulama sayfasında çalışan JavaScript programı ve verdiği sonuç, aşağıda görülmektedir:

...

function ekle(x) {
return function(y) {
return x + y;
}


function toplam() {

var topla = ekle(3); 

bilgiYaz(topla(7), 'b2.5.5-uyg-1-sonuç-1');

}

...
		

Sonuç :

Yukarıdaki uygulamada tanımlanmış olan topla() fonksiyonu, geriye bir anonim fonksiyon döndürmektedir. Bu anonim fonksiyon açık (bağlanmamış) bir x değişkeni içermektedir. Bu serbest değişken, bir üst kapsam alanındaki x değişkenin değerini bağlayarak kapalı bir devre oluşturmaktadır. Buna aynen termodinamikte dengede olmayan bir sistemin, en kısa ve en kolay yoldan dengeye ulaşmak istemesi gibi bakabiliriz.

Bundan sonraki ekle = topla(3); atama ifadesinde, topla fonksiyonu x argümanı için 3 değeri ile değerlendirilerek sonuç ekle değişkenine aktarılmaktadır. topla() fonksiyonu geriye anonim bir fonksiyon referansı döndürmektedir.

Bundan sonra ekle (7) ifadesi, iç fonksiyonu çalıştırmakta, dış kapsamdaki bağladığı x değişkeninin değerini okumakta, ve çağrıldığı argümanla toplamaktadır. Dış fonksiyon geriye değerini döndürüp işlevini tamamlamasına rağmen değişkenlerinin değeri kaybolmamakta ve iç fonksiyon, dış fonksiyonun bir değişkenine erişebilmektedir.

Yukarıdaki uygulamanın işleyişinin izlenmesi kolay değildir. Bu kodların daha da karmaşığı, bir uygulama sayfasında aşağıdaki sonuçları vermekte olan JavaScript programı kodlarında görülebilir:

...

function dışFonksiyon(x) {

function içFonksiyon(y) {

return x + y;
}

return içFonksiyon;
}

bilgiYaz(dışFonksiyon(7)(3), 'b2.5.5-uyg-2-sonuç-1');
...
		

Sonuç :

Yukarıdaki uygulamanın işleyişinin izlenmesi daha da güçtür. Burada ilk çağrı dış fonksiyona 7 parametresi ile yapılmaktadır. Bu çağrı, çağrının yapıldığı değişkene iç fonksiyonun çağrılabilme olanağını döndürmektedir. İkinci 3 parametresi iç fonksiyonu çağırmaktadır. Dış fonksiyon işlevini tamamlamış, değerini döndürmiüş ve çıkmıştır. Buna rağmen, JavaScript programlama diline özgü ve başka programlama dillerinde az bulunan bir saklama tarzı ile çıkmış olan dış fonksiyonun değişkenlerine iç fonksiyon erişebilmektedir. Bu durumda, iç fonksiyon dış fonksiyonun henüz erişilebilir durumda olan çağrı parametresi x değerine erişmekte, bunu kendi parametresi ile toplamakta (sistem kapanmakta) (denge durumu) ve sonucu döndürmektedir. Gerçekten bu çok "cool" bir işleyiştir.

Bu çok elegan görünümlü yöntemin sınırı yoktur. Fonksiyonlar istenildiğ kadar derinlikte içiçe yuvalanabilmekte, istenildiği kadar karmaşık yapıda kapalı devreler yapılabilmekte ve akla hayale gelmeyen uygulamalar yaratılabilmektedir. Bu yöntemin avantajları yanında çok da sakıncaları bulunmaktadır.

Bu sakıncaların en önemlisi, işin teknik yönüdür. Bir kapalı devrede global kapsam alanının altında bir dış onun da altında bir iç kapsam açılmaktadır. Normal olarak, fonksiyonlar, değerini döndürüp çıkınca ve programda artık bu fonksiyona başka çağrı yapılmıyorsa, yani çağrı kapalı ise, JavaScript yorumlayıcısının çöp toplayıcısı devreye girmekte ve bu bellek bölgesini temizleyerek genel programın kullanımına geri vermektedir. Kapalı devrelerde ise, bu kapsamlara, üst kapsam alanlarından çağrılar kapanmamaktadır. Hatırlandığı gibi, kapalı devreler, açık bir sistemdir, dengesizdir ve dengeye erişme gayreti içindedir, dengeye ulaşması için, üst kapsam alanının değişkenine gereksinmesi vardır ve bu çağrısını daima canlı tutar. Bu durumda JavaScript yorumlayıcısının çöp toplayıcısı, çağrının var olduğunu algılayıp kapalı devrenin işgal ettiği bellek alanını temizleyemez. Daha da kötüsü, dış bölgeden kapalı bölgeye yapılacak her çağrı, farklı parametrelerle yapıldığı için, farklı kapalı devreler açar, bu çağrılar özellikle bir döngü sisteminden yapılıyorsa, program belleği (stack memory) hızla tütetilebilir. Döngü olmasa da programda kapalı devrelere yapılacak her çağrı program belleğini kullanmaya devam eder. Buna bellek sızıntısı denilir ve sonunda program devreden çıkabilir. Özellikle Internet Explorer bu konuda daha da duyarlıdır.

Bellek sızıntısı sorunu, kapalı devrelerin gereksiz yere kullanımını kesin olarak engeller. Bellek sızıntısı yaratacağını bile bile ne kadar elegan ve profesyonel görünürse görünsün, hiçbir yöntem uygulanamaz. Bu yönteme ancak gerektiği zamanlarda ve kısıtlı olarak başvurulabilir. Özetle, genel olarak, programlarda içiçe fonksiyon tanımlarından kaçınmak gerekir.

Kapalı devrelerde dikkat edilmesi gereken konulardan birisi de, isim çakışmalarıdır. İçiçe kapsamlarda değişkenlerin adları aynı olursa, bu bir isim çakışmasına neden olur. Çakışan değişken isimlerinin içeriği, kapsam değiştikçe değişir ve öncelik en iç kapsama verilir. Bu durumda, programda mantık hataları ortaya çıkabilir ve bilindiği gibi mantık hataları izlenmesi, farkında olunması ve düzeltilmesi en zor olan bazen yıllarca farkedilemeden zarar vermeye devam edebilen hatalardır. Bu hataların oluşabilmesine olanak vermemek için alınacak önlemlerden biri de bilinçsiz isim çakışmalarına neden olunmamasıdır.

Yakın bir tarihte Stuart Langridge kapalı devrelerin çok güçlü programlama araçları olduğunu ve vadettikleri gelişmeleri iki video konferansı halinde açıklamaktadır. Çok ileri düzey uygulamalarını içeren bu açıklamalar, belki normal kullanıcılar için fazla anlaşılabilir olmayacaktır. Diğer taraftan, Douglas Crokford başka hiçbir yöntemle gerçekleştirilemeyecek nesne sınıfları için private members yaratılabilmesinin kapalı devreler ile gerçekleşebileceğini göstermiştir. Bir başka kapalı devreler taraftarı da DustinDiaz olarak belirtilebilir. Diğer taraftan, Nicolas Zakas bu tür programların JavaScript programlama dilinin amaçları dışına taştığını, zor okunan karışık programlar yarattığını, bunların normal yöntemlerle de programlanabileceğini düşünmektedirler.

Genel olarak, kapalı devreleri kullanmaktan kaçınan programcılar,

belirterek, kapalı devreleri kullanmakatan kaçınmaktadırlar. Aslında, küçük programlar için, çekinilecek hiçbir şey yoktur ve uygulamacılar kapalı devreleri -dikkatli olmak koşulu ile- özgürce kullanabilirler.

Kapalı devrelere klasik bir örnek olarak, JavaScript kodları aşağıda görülen bir uygulama verilmiştir.

/* <![CDATA[  */
			
/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */


function söylem1(metin) {

var sözler = 'Bugün 23 Nisan \n' + metin;

var söyle = function() {

alert(sözler);

}

return söyle;
}



function mesaj1() {

var bildiri = söylem1('Büyük Millet Meclisi Bugün Kuruldu !');// Dış Fonksiyon

bildiri();// İç Fonksiyon

return false;// Çapa Elementinin href Niteliği İptal Edilliyor !
}


function başlat1(){

var a = document.getElementById('tab1');

a.onclick = mesaj1;
}


sayfaYüklendiktenSonraÇalıştır(başlat1);

/*   ]]>  */
		

Yukarıdaki uygulamanın, JavaScript kodları incelendiğinde sadece söylem() fonksiyonunun kapalı devrelerle ilgili olduğunu, programın diğer kısımlarının, programın interaktivitesini sağlamak amacı ile eklendiği görülebilir. Bu fonksiyonun tanım alanında bir iç söyle() fonksiyonu olduğunu ve bu iç söyle fonksiyonun, dış söylem() fonksiyonunun sözler değişkenini kullandığını görülmektedir. Bu bir klasik kapalı devredir.

Çok sıradışı bir başka kapalı devre uygulamasının JavaScript kodları ve uygulama sonuçları aşağıda görülmektedir:

/* <![CDATA[  */
			
/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */


function söylem2(metin) {

var sözler = 'Bugün 23 Nisan \n' + metin;

var söyle = function() {

alert(sözler);

}

return söyle;
}



function mesaj2() {

söylem2('Neşe Doluyor İnsan !')();// Dış ve İç Fonksiyon

return false;// Çapa Elementinin href Niteliği İptal Edilliyor !
}




function başlat2() {

var a = document.getElementById('tab2');

a.onclick  = mesaj2;
}


sayfaYüklendiktenSonraÇalıştır(başlat2);

/*   ]]>  */
		

Bu uygulamada söylem() fonksiyonun bellek alanında bulunan söyle değişkeninin referansı olan fonksiyonun döndürdüğü değere erişim için çok sıradışı () () çift gruplama operatörü kullanılmıştır. Bu uygulamanın, yardımcı değişken kullanılan bir önceki uygulamadan tek farkı doğrudan çağrı yapılmış olunmasıdır. Bu çok sıradışı çağrı içeren son uygulamayı, sıradan bir kapalı devre uygulaması haline getirerek sıradan bir çağrı içermesini sağlayan JavaScript kodları aşağıda görülmektedir :

/* <![CDATA[  */
			
/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */


function söylem3(metin) {

var sözler = 'Bugün 23 Nisan \n' + metin;

var söyle = function() {

alert(sözler);

}

return söyle;
}



function mesaj3() {

söylem3('Neşe Doluyor İnsan !');// Dış ve İç Fonksiyon

return false;// Çapa Elementinin href Niteliği İptal Edilliyor !
}




function başlat3() {

var a = document.getElementById('tab3');

a.onclick  = mesaj3;
}


sayfaYüklendiktenSonraÇalıştır(başlat3);

/*   ]]>  */
		

Aynı işlevi, kapalı devre oluşturan iç fonksiyonuna gerek olmadan çözümleyen uygulamanın JavaScript kodları aşağıda görülmektedir:

/* <![CDATA[  */
			
/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */


function söylem4(metin) {

var sözler = 'Bugün 23 Nisan \n' + metin;

alert(sözler);

}



function mesaj4() {

söylem4('Neşe Doluyor İnsan !');// Dış ve İç Fonksiyon

return false;// Çapa Elementinin href Niteliği İptal Edilliyor !
}




function başlat4() {

var a = document.getElementById('tab4');

a.onclick  = mesaj4;
}


sayfaYüklendiktenSonraÇalıştır(başlat4);

/*   ]]>  */
		

Kodlardan görülebileceği gibi, kapalı devrelerden kaçınmak için çoğu zaman bir yol bulunabilmektedir. Eğer bir işlevin yapılabilmesi için gereken kodlar, kapalı devreler olmadan çözümlenebiliyorsa, kapalı devrelere başvurulmayan yöntemin uygulanması daha uygun olacaktır.

Kaplı devreler konusunda, günümüzdeki gelişmeler, bu yöntemlerin giderek attığını ve hergün daha çok kapalı devrelerin uygulandığı yöntemlerin açıklandığı yönündedir. Bu çalışma alanının yeni olması, insanların yeni şeyleri keşfetme içgüdülerini büyük ölçüde etkilemiş görünmektedir. Son bilgiler, bellek sızıntılarının korkulacak kadar olmadığını, web sayfalarından çıkılınca, ortadan kalkacağını belirtmektedir. Yine de, başka yöntemlerle yapılabilecek çalışmalar için, kapalı devrelerin kullanılmasından kaçınmak şimdilik uygun bir davranış olacaktır.

Kapalı devreler hakkında temel bilgileri burada inceledik ve artık konu ile ilgili genel bir bilgi almış durumdayız. Kapalı devreler (Closures) konusu çok geniş ve çok kuramsaldır. Bu konu çok aktif olarak çalışılmakta ve yeni bilgiler yayınlanmaktadır. Bu konu ile ilgili, daha fazla bilgi için, Richard Cornford tarafından yazılmış olan kuramsal incelemenin, çok güzel bir JavaScript tanıtımı olan Douglas Crockford 'un incelemesinin ve Internet Explorerdeki Bellek Kaçakları (Memory Leaks) probroblemlerinin kapalı devrelerle azaltılabilmesini açıklayan Volkan Özçelik tarafından yazılmış incelemenin okunması sağlık verilebilir. Buradaki incelemeler, daha çok, Morris Johns ve SachinKumarK tarafından yapılmış açıklamalardan yararlanılarak hazırlanmıştır.

2.5.6 - Fonksiyonların Koşullu olarak Oluşturulmaları

Fonksiyonların bir koşulun gerçekleşmesi ile yaratılması bazen yararlı olabilir. Özellikle, ismi aynı fakat içeriği farklı olan fonksiyonların yaratılması için, koşullu ifadeler yararlı olacaktır. Fonksiyonların, fonksiyon bildirimi ile koşullu ifadeler ile yaratılmaları bazen yanıltıcı sonuçlar verebilmektedir. Bu konuda bir JavaScript programı ve bağlantılı olduğu uygulama sayfasında verdiği sonuç, aşağıda görülmektedir:

...

var f = false, k = null;
if( f===true) {
function d() {
return 99;
}

k = d;

if (typeof k=='function') {

bilgiYaz(k(), '2.5.6-uyg-1-sonuç-1');

}

else {

bilgiYaz('Fonksiyon Oluşturulmadı!', '2.5.6-uyg-1-sonuç-1');

}

...
		

Sonuç : Internet Explorer99
FireFoxHata !

Bu uygulamada, if bloğu içinde yapılan fonksiyon tanımı, bir fonksiyon bildirimi gibi görünmesine karşın, bir fonksiyon literalidir. Çünkü bir ifade içinde tanımlanmaktadır. Normal olarak bu fonksiyonun tanımlanmamış olması gerekir, çünkü, mantıksal koşul gerçekleşmemiş olduğundan, program akışı tanımın yapıldığı if bloğu içinden devam etmemektedir. Bu durumda, programın fonksiyonun oluşmadığı şeklinde mesaj vererek çıkması gerekir. Bu beklenen davranış sadece FireFox tarafından gösterilmektedir. Internet Explorer, Chrome, Safari, Opera, belge çözümleyicilerin en son sürümleri, fonksiyonu tanımlanmış olarak kabul ederek sonucu görüntülemektedirler. Durum gerçekten çok can sıkıcıdır.

Belge çözümleyicilerin JavaScript yorumlayıcıları arasındaki bu değerlendirme farkını ortaya çıkmasının nedeni yukarıdaki programın kendisidir. Bu programda, bir ifade içinde fonksiyon tanımına çalışılmıştır. Halbuki ECMA-262 sürüm 3 final spesifikasyonu, fonksiyon tanımının sadece global alan ve fonksiyon alanları içinde ve ifade ve döngüler dışında yapılmasını öngörmektedir. Bu durumda, if bloğu içinde yapılan fonksiyon bildirimi tanımı yasal değildir ve gerçekte bir fonksiyon literalidir. Bu yüzden bazı belge çözümleyicilerin JavaScript yorumlayıcıları bu ifadeyi bir ifade kabul edip fonksiyon tanımını yapan bloğu atlamakta, büyük bir çoğunluk ise, bunu bir fonksiyon bildirimi kabul edip, istenilenin aksine, fonksiyonu tanımlayarak hesapladığı sonucu görüntülemektedirler.

Bu programın istenilen yönde, çalışmasının sağlanması için alınacak tek önlem bulunmaktadır. Bu önlem, spesifikasyonda öngörüldüğü gibi, fonksiyon tanımlarını, if ve döngü blokları içinden yapmamak bu blokların içlerinde fonksiyonları sadece fonksiyon literali olarak tanımlamaktadır. Bu şekilde, mantıksal program akışı, tanımın yapıldığı karar bloğununa girmeden devam edecek ise, fonksiyon da kesin olarak tanımlanmış olmayacaktır. Bu konuda bir JavaScript programı ve bağlantılı olduğu uygulama sayfasında verdiği sonuç, aşağıda görülmektedir:

...

var f = false, k = null;
if( f===true) {
k = function() {
return 99;
}

if (typeof k=='function') {

bilgiYaz(k(), '2.5.6-uyg-2-sonuç-1');

}

else {

bilgiYaz('Fonksiyon Oluşturulmadı!', '2.5.6-uyg-2-sonuç-1');

}

...
			

Sonuç :

Bu son uygulama sonucu, aynı zamanda bir uyarı niteliğindedir. Eğer bir fonksiyonun mantıksal bir ifade sonucu tanımlanması isteniyorsa, mantıksal blok içinde, fonksiyonu anonim bir fonksiyon olarak tanıtmak zorunludur.

2.5.7 - Özyineleme (Rekürsiyon)

Özyineleme bir fonksiyonun kendi kendini çağırmasıdır. Özyineleme uygulanan yöntemlere, özyinelemeli (rekürsif) yöntemler adı verilir. JavaScript programlama dilinin fonksiyonları, birinci sınıf nesnelerdir ve özyinelemeye yeteneklidir.

Özyinelemeli yöntemler, bilgisayar programlama konusunun en geniş konularından biridir. Çoğu bilgisayar yöntemleri, özyinelemeli olarak da tasarlanabilirler. Bir zamanlar çok popüler olan PROLOG programlama dili, tamamen özyinelemeli yöntemlere dayanmaktadır.

Rekürsif yöntemlerin programlanması ve rekürsiyona dayalı olarak yazılmış programların bakım için yeniden deşifre edilmeleri zordur. Bu yüzden programların daha kolay izlenebilen klasik yöntemler kullanılarak yapılmasına devam edilmektedir. Yine de faktoryel hesabı gibi bazı önemli programlar için rekürsif yöntemler tercih edilmektedir.

Özyinelemeli yöntemler, bir tür döngü sistemi gibidir. Özellikle while döngüleri ile gerçekleştirilen yöntemlerin, özyinelemeli yöntemler olarak tasarlanması olanağı bulunabilir. Her döngü sistemi gibi, özyinelemeli yöntemlerden de çıkış için bir mekanizma tasarlanmalıdır. Aksi takdirde, tüm döngü sistemleri gibi özyinelemeli yöntemler de sonsuz döngülere neden olarak, programın devreden çıkmasına sebep olabilirler.

Tasarım ve izleme güçlüklükleri ve genellikle, özyinelemeli yöntemlerle yapılan çalışmaların, klasik yöntemlerle de gerçekleştirilebilmesi nedeni ile, çalışmalarımızda özyinelemeli yöntemler uygulanmayacaktır. Bir örnek olarak, ilişkilendirildiği uygulama sayfasında çalışan bir JavaScript Programı özyinelemeli bir yöntemle, faktoryel değerlerinin hesaplanmasını yapmaktadır. Faktoryel değerleri, pozitif sayıların, kendilerinden küçük pozitif sayılarla çarpımlarının sonucudur. Örnek olarak , 3! = 3 * 1 * 2 işleminin sonucu olan 6 değeridir.

Yukarıdaki JavaScript programı, interaktif bir programdır. Bu programda özyinelemenin gerçekleştiği fonksiyon, yazılımı aşağıda görülen faktoryel() fonksiyonudur.

...

function faktoryel(x) {
			
if (x === 1) {
return 1;
}

else {
return x * faktoryel(x - 1);
}
}
...
		

Bu fonksiyonun return bildirimi, eşdeğer olarak,

...
return x * arguments.callee(x - 1);
...
		

olarak da ifade edilebilir. arguments.callee öntanımlı fonksiyon argümanları nesnesinin öntanımlı bir özelliğidir. Fonksiyon içeriğinde, this sözcüğü, fonksiyonun kendisine işaret etmez. Bunun yerine arguments.callee özelliği kullanılır. Bu özelliğin, isimli fonksiyonlarda kullanımı gereksizdir, fakat, isimsiz (anonim) fonksiyonlarda rekürsiyonunun sağlanabilmesi amacı ile kullanılır. Doğal olarak, özyinelemeamaçlı fonksiyon literalleri, isimli fonksiyon literalleri olarak da oluşturulabilir.

2.5.8 - JavaScript Olay Yöneticilerine Fonksiyonların Atanması

Bölüm 1.3 de, (X)HTML sayfa elementleri ile etkileşimli JavaScript programlarının, kullanıcılarla karşılıklı etkileşimli (interaktif) programlar oluşturmak için olay yöneticilerinden yararlanma yöntemleri açıklanmış ve en son JavaScript programı örneğinde olduğu gibi, karşılıklı etkileşimli (interaktif) programlar yapılabildiğini belirtilmişti. Olay yöneticilerinden yararlanılarak karşılıklı etkileşimli programların çalışma yöntemi, asenkron olay yönetimi modelidir. Bu çalışma şekli, kullanıcıların etkilerinin olay yöneticileri tarafından yakalanması ve önceden programlanan tepkilerin verilmesidir.

Olay yöneticilerine, dinledilkleri olay gerçekleşince yapacaklarını belirten fonksiyonların bağlanmasıdört faklı yöntemle gerçekleştirilebilir. Bunlar,

İlk olarak, (X)HTML elementlerinin olay dinleyici niteliklerine fonksiyon atanması, Bölüm 1.3 de de açıklandığı gibi, (X)HTML sayfa işaretleri ile JavaScript programlama adımlarının aynı sayfada, yanyana çalıştırılmalarını gerektirecekir. Oysa, engellemeyen JavaScript (Unobtrusive JavaScript) prensibine göre, sayfanın (X)HTML kodlarında karışıklık yaratılmaması için, (X)HTML sayfa işaretleri arasına hiçbir başka program yazılımı konulmamalıdır. Bu nedenle bu yöntem artık kullanılmamaktadır.

İkinci yöntem, Javascript program adımlarından (X)HTML sayfa elementlerine erişilmesi ve Javascript olay yöneticilerine çalıştıracakları fonksiyonların atanması yöntemidir. Bu yöntem, engellemeyen JavaScript prensibine uygundur. Tüm programlama, sayfaya bağlantılı bir JavaScript program sayfasından yürütülebilmekte ve sayfanın (X)HTML kodlarında karışıklık yaratacak yabacı kodlar görülmemektedir. Sayafa elementlerine erişim, ileride ayrıntılı olarak inceleyeceğimiz W3C-DOM yöntemlerine göre yapıldığında, tüm belge çözümleyicilerce ortak olarak desteklenecektir. Bu nedenle, bu yöntem, uygulanabilir bir yöntem olarak ortaya çıkmaktadır.

Üçüncü yöntem, yine W3C tarafından geliştirilmiş bir yöntemdir. Bu yöntem, olay yöneticilerine belirli fonksiyonların atanabilmelerini bir sisteme bağlayan ve rasyonelleştiren bir yöntem olarak geliştirilmiştir. Bu yöntem ne yazık ki sadece FireFox ve onu izleyen belge çözümleyiciler tarafından desteklendiği için genel uygulanma desteğinden yoksundur. Burada bu yöntemi de inceleyeceğiz, çünkü standartlar sonunda mutlaka desteklenir. Microsoftun bu standardı desteklememesi, standartların geliştirildiği ve herkesin bu standartlara uymayı uygarlık gereği olarak gördüğü günümüzde, geçerli bir davranış değildir.

Dördüncü ve en son yöntem, Microsoft tarafından geliştirilen yöntemdir. Bu yöntem, sadece Internet Explorer tarafından desteklenmektedir. Genel destekten yoksun olduğundan, bu yöntem genel amaçlı sayflarda kullanılamaz.

Bu durumda, sadece ikinci yöntem, yani, sayfa elementlerine JavaScript programlarından erişilmesi ve JavaScript olay yöntecilerine JavaScript fonksiyonları atanması, yani herşeyin sadece JavaScript tarafında yürütülmesi, ortak olarak desteklenebilen tek yöntem olarak öne çıkmaktadır. Burada ağırılık bu yönteme verilecektir. W3C yöntemi de ileride genellik kazanma olanağı olduğundan burada tanıtılacaktır.

JavaScript program adımlarından (X)HTML sayfa elementlerine erişilme yöntemleri, ECMA-262 sürüm 3 tarafından belirtilmemiştir. Bu yöntemler, Belge Nesne Modeli olarak tanılanan ve JavaScript global nesnesini, window nesnesi olarak yerleştiren özel belge çözümleyici yazılımları ile ilgilidir. Bu yöntemler, W3C-DOM olarak standartlaştırılmıştır. Burada da W3C-DOM yöntemleri kullanılarak sayfa elementlerine JavaScript program adımlarından erişierek genel olarak desteklenecek yöntem oluşturmaya önem verilmiştir. Javascript program adımları, sayfanın elementlerine, DOM (Document Object Model) adı verilen bir yerleştirme modelini izleyerek erişirler. Tüm belge çözümleyicileri, standartlaştırılmış W3C-DOM belge nesne modelini desteklediklerinden, JavaScript bu modelden yararlanılarak sayfa elementlerine erişebilir. Doğal olarak, başka modellerden de yararlanılabilir. Bu çalışmanın ileri aşamalarında belge nesne modeli ayrıntılı olarak incelenecektir. Burada, sadece, sayfa elementlerine erişilerek Javascript olay yöneticilerine çalıştıracakları fonksiyonların atanması üzerinde durulacaktır.

DOM modelinde varsayılan window nesnesi altında, document nesnesi tüm sayfa elementlerine erişim sağlar. Herhangibir sayfa elementinin id değerinden yararlanılarak,

var a = document.getElementByID(elementinIdDeğeri);
		

şeklinde erişilebilir. Daha esekiden uygulanan erişim yöntemleri de ileride açıklanacaktır. Yukarıdaki program adımı ile a değişkeni, bir sayfa elementinin yerine geçer ve kendisine JavaScript programlama dilinde, öntanımlı olay yöneticileri özellik olarak kalıtımla aktarılır.

JavaScript programlama dilinde, öntanımlı JavaScript (X)HTML sayfa elementlerinin, olay yöneticilerinin işlevini yapar. JavaScript olay yöneticileri ,on ön eki ile başlar, örnek olark, onclick, ondblclick, onfocus, onblur, onload, onunload gibi olay yönetecileri bulunmaktadır. Bur ada örnek olarak window.onload olay yöneticisini ele alacağız. Bu olay yöneticisi, sayfa elementlerinin tümünün yüklenmesini kontrol eder ve yüklenme tamamlandığında, kendisine atanan fonksiyonu çalıştırır.

JavaScript olay yöneticilerinin, başlangıçta değerleri Intenet Explorer için null, FireFox için undefined dir. Bu konuda bir JavaScript programı bir uygulama sayfasında aşağıda görülen sonucu vermektedir:

...
bilgiYaz(window.onload, 'b2.5.8-uyg-1-sonuç-1');
...
		

Program Sonucu :

null (IE) , undefined (FireFox)

olarak elde edilir.

Sayfa içinde , id değeri, "buton1" olan bir input elementi olduğunu varsayalım, bu elemente W3C-DOM yöntemi ile erişim,

 window.document.getElementById('buton1');
		

şeklindedir. Burada window nesnesi, Global JavaScript Nesnesi olarak hareket ettiğinden varsayılan nesne olarak kabul edilirse, ifade sadece,

 document.getElementById('buton1');
		

olarak kalır. Bu düğmenin basılması ile harekete geçen olay, onclick olay yöneticisinin değeridir. Bu değer olarak bir fonksiyon atanırsa, düğmeye tıklandığında fonksiyon çalışır. Örnek olarak düğmeye tıklandığında bir alert mesajı verilmek istendiğinde , aşağıdaki atamayı yapmak yeterli olacaktır:

 document.getElementById('buton1').onlick = function() {
alert('Merhaba Dr. Chandra'); 
}
		

Bu atamadan sonra, buton1 nesnesinin onload niteliğinin değeri bir anonim fonksiyon ve veri tipi de "function" olacaktır. Bu ifade biraz uzun görülürse, olay yöneticisi önceden bir değişkene atanabilir. Bu örnekteki buton1 nesnesinin onclick özelliği, her nesne özelliği gibi bir değişkene atabilir. Doğal olarak, değişkene atanan değer, nesne özelliğinin bellek adresinden ibarettir. İşlem,

var uyarı = document.getElementByID('buton1');
			
uyarı.onclick = function() {
alert('Merhaba Dr. Chandra'); 
}
		

şeklinde kısaltılabilir. Daha da doğrusu, fonksiyonu ismli bir fonksiyon olarak önceden tanımlamak ve fonksiyonun bellek adresinin bir kopyasını, olay yöneticisinin atanmış olduğu değişkene atamaktır. Bu işlem, aşağıda kodları görülen JavaScript programı ile gerçekleştirilmiş ve bir uygulama sayfasında aşağıda görülen sonuçlar alınmıştır:

function uyarı() {
alert('Dikkatli Olun \n Dr. Chandra !');
}

...
var düğme = document.getElementById('buton1');
düğme.onclick = uyarı;
...
		

Program sonuçlarından, her türlü JavaScript olay yöneticisinin kolaylıkla programlanabileceği görülebilmektedir. Yöntem etkili ve engellemeyen türdedir, ayrıca platformlararası geçerli olan tek yöntemdir. Burada tek dikkat edilecek nokta olay yöneticisine bir fonksiyon atarken, örnek olarak,

window.onload = başlat;
		

şeklinde fonksiyonun çağrı adresini atamaktır. Eğer aşağıda görüldüğü gibi, atamada çağrı işlemcisi () kullanılırsa,

window.onload = başlat();
		

Bu yanlış olur, çünkü olay yöneticisine fonksiyonun bellek adresi yerine, fonksiyonun döndüreceği değer atanmış olur.

Üçüncü yöntem olan, W3C tarafından geliştirilmiş olan, addEventListener() fonksiyonu üzerinde de durulması gerekir. Bu fonksiyon günümüzde ne yazık ki sadece FireFox ve takipçileri tarafından destekleniyor ve Internet Explorer desteklemediği için platformlararası olmak niteliğini kazanamıyor. Buna rağmen iyi bir standart olduğundan ileride destekleneceği düşünülebilir. Bu fonksiyonun uygulanmasını, sonuçları aşağıda görülen bir uygulama sayfasına bağlantılı bir JavaScript programından izleyelim:

function tanıtım() {
alert('Merhaba \n Ben HAL !');
}

var düğme = document.getElementById('buton1');
düğme.addEventListener('click', tanıtım, false);

addEventListener() Fonksiyonunun ilk argümanı olay yöneticisi, ikincisi atanacak fonksiyon, üçüncüsü daima false olarak kullanılabilecek bir parametredir. Bu uygulama şimdilik sadece FireFox da çalışabilmektedir.

Microsoft tarafından geliştirilmiş ve sadece Internet Explorer de çalışan yöntem :

function tanıtım() {
alert('Merhaba \n Ben HAL !');
}

var düğme = document.getElementById('buton1');
düğme.attachEvent('click', tanıtım);

attachEvent() Fonksiyonunun ilk argümanı olay yöneticisi, ikincisi atanacak fonksiyondur.

W3C tarafından tanımlanan attachEvent() fonksiyonun, MS Internet Explorer tarafından desteklenmemesi, olay yönetiminin tüm belge çözümleyicilerde desteklenmesi amacı ile ortak dessteklenebilecek bir program geliştirilmesi gereğini yaratmıştır. bu program aşağıda görülmektedir.

function olayDinleyicisiEkle(elm, olay, fonksiyon) {

// Eğer Belge Çözümleyici FireFox Tipi İse (GECKO Motoru)

if(elm.addEventListener) {
elm.addEventListener(olay, fonksiyon, false);
return true;
}

// Eğer Belge Çözümleyici Internet Explorer İse

else if(elm.attachEvent) {
olay = 'on' + olay;
var r = elm.attachEvent(olay, fonksiyon);
return r;
}
		
// Eğer Belge Çözümleyici Farklı İse

else{
elm['on' + olay] = fonksiyon;
}
}
		

Burada geliştirilmiş olan olayDinleyicisiEkle() fonksiyonundan yararlanılarak, sayfa yüklendikten sonra JavaScript fonksiyonlarının çalıştırmaya başlayacak olan bir fonksiyon aşağıdaki gibi düzenlenebilir:

function sayfaYüklenmesiTamamlandıktanSonraÇalıştır(fonksiyon) {
olayDinleyicisiEkle(window, 'load', fonksiyon);
}
		

Burada geliştrilmiş olan olayDinleyicisiEkle() ve sayfaYüklenmesiTamamlandıktanSonraÇalıştır()fonksiyonları, bdelib.js kitaplığına eklenmiş ve uygulamalarda kullanılmaya hazır durumdadırlar.

Son olarak 1.3.6 bölümünde incelenmiş olan ve Simon Willison tarafından yazılmış olan, window.onload olay yöneticisini kullanılarak, sayfa yüklendikten sonra, çalışması gereken fonksiyonları sıra ile çalıştıracak bir fonksiyon olan aşağıda görülen fonksiyonu yeniden incelemekte yarar olacaktır.

function sayfaYüklendiktenSonraÇalıştır(çalıştırılacakFonksiyon) {
var öncekiFonksiyon = window.onload;
if(typeof window.onload != 'function') {
window.onload = çalıştırılacakFonksiyon;
}
else {
window.onload = function() {
öncekiFonksiyon();
çalıştırılacakFonksiyon();
};
}
}
		

Bu fonksiyon , ilk olarak bir öncekiFonksiyon değişkenine window.onload olay yöneticisinin başlangıç değerini atamaktadır. Bu değer, eğer önceden bir fonksiyon atanmamışsa null olacaktır. Yazar, daha sonra bu değerin tipini kontrol etmekte ve değerin veri tipi bir fonksiyon veri tipi değilse, argümanı bu olay yöneticisine atamakta ve program tamamlanmaktadır. Eğer, önceki değer bir başka fonksiyon ise, o zaman olay yöneticisine bir fonksiyon literali atanmakta ve bu bir kapalı devre açmaktadır. Bu kapalı devre, üst fonksiyon kapsam alanından, henüz bellekte saklanmakta olan öncekiFonksiyon değişkenininin değeri olan önceki fonksiyonun bellek referransını okumakta ve önce bu fonksiyonu ardından da argümandaki fonksiyonu çağırmaktadır. Bu fonksiyon sadece iki fonksiyonluk bir kuyruk oluşturmakta, fakat istendiği kadar sayfaYüklendiktenSonraÇalıştır() fonksiyonu kullanılabildiğinden, sayfa yüklendikten sonra çalışmak üzere istendiği kadar uzun bir fonksiyon kuyruğu oluşturulabilmektedir.

2.5.9 - Fonksiyonların Argüman Olarak Kullanılması

Javascript programlama dilinde fonksiyonlar birinci sınıf nesnelerdir ve bunun sonucu olarak, başka fonksiyonlarda argüman olarak kullanılabilirler. Uygulamada büyük olanaklar sağlayan bu yöntem, Javascript programlama dilinin bir üstünlüğüdür. Bu konuda bir JavaScript programı ve bağlantılı olduğu uygulama sayfasında verdiği sonuç, aşağıda görülmektedir:

...

functionsayılarıTopla(x, y) {
return x + y;
}

sonuçYaz('3 +5 = ', sayılarıTopla(3, 5), 'b2.5.9-uyg-1-sonuç-1');
...
		

Program Sonucu :

Valid XHTML 1.1