JavaScript Temelleri

Bölüm 2

Temel Bilgiler

2.7 - Aritmetik İşlemciler

Bölüm 2 Sayfa 7

2.7.1- Veri Tipi Uyarlaması (Coercion)

Javascript programlama dilinin veri tipilerinin belirtilmediği bir programlama dili olması, yüzeysel bir gözlemdir ve sadece kullanım kolaylığı açısından düşünülmelidir. Bu görüntünün tam aksine, JavaScript yorumlayıcısı, veri tiplerini sürekli izler, belirli bir veri tipi kullanılması gerekli olan işlenen veri tiplerini, metotların argüman veri tiplerini ve başka belirli veri tipi gereken her yerde, verilerin tipleri işleme uygun değilse, işleme uygun olacak veri tiplerine dönüştürmeye çalışır. Bu yönteme veri tipi uyarlaması veya basitçe uyarlama (coercion) adı verilir.

JavaScript tip uyarlamları bazı durumlarda çok açık ve yönü bellidir. Bu uyarlamalar, sorunsuz gerçekleşir. Bazı durumlarda ise, uyarlama kullanıcının öngördüğü yönde gerçekleşmeyebilir. Bu durumlarda, sonuçların kontrol edilmesi ve gerekirse, kullanıcıların kendilerine sağlanmış açık (explicit) tip dönüştürme yöntemlerinden yararlanarak verilerinin tiplerini kendileri düzenlemeleri ve JavaScript yorumlayıcısına uyarlama zorunluğu bırakmamaları gerekir.

Javascript yorumlayıcısının uyarlama yeteneği, adaptive bir yöntemdir ve bir programlama dili için, esneklik sağlayan ileri bir yöntemdir. JavaScript yorumlayıcısının bu üstün uyarlama yeteneği, bazen yanlış sonuçlara neden olabilir.

Javascript programlama dili, güçlü veri tipi kontrolü yapılan Java programlama dili gibi değildir. Java programlama dilinde bir verinin tipi öngörülen işleme uygun değilse, program devreden çıkar. Javascript programlama dilinde ise, aynı durum uyarlama ile sonuçlanır ve program bir sonuç üretebilir. Javascript programlamasında, sonuçlar daima kontrol edilmeli ve uyarlamaların doğru yönde geliştiği garanti edilmelidir.

2.7.2- Tek İşlenenli (Unary) İşlemciler

Tek işlenenli işlemciler, sadece sol işlenen alırlar. Bu işlemciler, tekli işlemciler listesinde verilmişlerdir. Bu listedeki aritmetik işlemciler aşağıdaki tabloda listelenmiştir.

Tekli Aritmetik İşlemciler
İşlemci Adı
+ Tekli Artı (Unary Plus) İşlemcisi
- Tekli Eksi (Unary Minus) İşlemcisi
++ Arttırma (Increment) İşlemcisi
-- Eksiltme (Decrement) İşlemcisi
void void (Boşluk) İşlemcisi

Tekli artı işlemcisi +, cebirsel tekli artı işareti gibidir. JavaScript yorumlayıcısı, cebirde olduğu gibi, sayıları varsayılan olarak pozitif kabul eder. Bu durumda, tekli artı işaretinin kullanılması gereği olmamasına karşın, kullanıcının istemesi halinde kulanılmasına bir engel yoktur. İstendiğinde,

değişkenAdı = + ifade;
		

şeklinde kullanılabilir. Burada ifade, sonucu sayısal olan ifadeler olabilir. Tekli artı işlemcisi +, hiçbir işlem yapmaz sadece argümanı olan ifadeyi değerlendirir. Önemli bir ayrıntı olarak, eğer ifadenin sonucu, sayıya dönüşenilen bir karakter dizigisi tipinde olursa, bunu bir sayısal veri tipine dönüştürür. Bu işlevi vurgulayan bir uygulamanın, JavaScript kodları aşağıda görülmektedir.

/* <![CDATA[  */

/* Bu Program bdelib-style.js Kitaplık Programını Kullanmaktadır */

function sözeldenSayısala_1(x) {

return + x;

}

function başlat() {

var a = '1204';
a = sözeldenSayısala_1(a);

veriTipiYaz(a, 'b2.7.2.1-uyg-1-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

Bu kodlarda kullanılan veriTipiYaz() fonksiyonu, bdelib.js kitaplığındaki yazdırma fonksiyonlarından biridir. Bu fonksiyon veri değerini ve veri tipini, sayfanın içerik kabul edebilir, id değeri belirtilen bir elemanının içeriği olarak yazdırmaktadır. Bu fonksiyonu henüz sadece kullanacağız. Bu fonksiyonun açıklanması, b20.3.3 konusunda yapılmıştır. İleride bu gibi fonksiyonların yazılımını kolayca gerçekleştirebilecek yöntemleri özümsemiş olacağız.

Yukarıdaki uygulamanın belirttiği gibi, tekli artı, bir zorlamalı uyarlama sağlayan açık (explicit) tip dönüştürücüsüdür. Javascript programlama dilinde bu gibi, kullanıcının serbestçe kullanabileceği açık tip dönüştürücü yöntemlerden biridir. Bu uygulamanın sonucunda, a değişkeninin veri tipi, sözelden (string) sayısala (number) dönüştürülmüştür. Argüman sayısala çevrilemezse, tekli artı işlemcisi, NaN (Not A Number) değerini döndürür.

Javascript programlama dili, sıkı veri tipi belirtilmesi gereken Java gibi bir programlama dili değildir. Tam aksine Javascript programlama dili, gevşek veri tipi izlenen ve yüksek uyarlama yeteneği ile açık tip dönüştürmesine çok az gereksinme duyulan bir programlama dilidir. Javascript programlama dilinde, açık tip dönüştürmesine sadece uyarlamaların istenen yönde gelişmeme olasılığı nedeni ile başvurulur.

Tekli eksi işlemcisinin önemi büyüktür. Tekli eksi işlemcisinin kullanımı cebirde olduğu gibidir. Tekli eksiişareti kullanılırken sadece çarpma *, bölme / ve modulu % işlemcileri birlikte kullanılabilir. Eşit işlemcisi = ile kısayol işlemcisi oluşturduğundan birlikte kullanılmaz. Tekli eksi işaretinin kullanıldığı bir uygulama, fonksiyon kitaplıkları konusunda yapmış olduğumuz, örneğinde epsilon argümanını eksi bir değer olarak vermek olacaktır. Bu uygulamanın JavaScript kodları aşağıda verilmiştir.

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

var geo = { 
türev : function (a, b, eps) {
return (a(b + eps) - a(b)) / ((b + eps) - b) ;
}
};
function başlat() {

var q = fonction(x) {
return x * x + 5 * x;
}

bilgiYaz(geo.türev(q, 2, -0.0000001), 'b2.7.2.2-uyg-1-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

JavaScript kodları yukarıda görülen uygulamanın, sonucunda a(x) fonksiyonun b[x] noktasında türevinin sayısal değerine, aşağı değerlerden de yaklaşılmasına olanak sağlamıştır. Hem 2.6.7-uyg-1.htm uygulamasının, hem de yukarıdaki uygulamanın verdiği sonuçlardan, a(x * x + 5 * x) fonksiyonunun, b[2] noktasında türevinin mevcut olduğu ve noktanın hem üstünde, hem de altında tannmlı olduğunu belirtmektedir. Bu her iki uygulamanın bir sondaj çalışması olduğunu, tek bir değerin hesaplanması ile yetinildiğini belirtmek yerinde olur. Gerçek sayısal türev yaklaşımı, iteratif bir algoritma ile gerçekleştirilir ve ileride iteratif yöntemler incelenirken bu konuda çeşitli örneklerle çalışma olanağı bulacağız.

Tekli eksi işlemcisi de, aynı tekli artı işlemcisi gibi, açık tip dönüşümü sağlayan bir işlemcidir. Argümanının sayısala dönüştürülebilir bir sözel tipte veri olması durumunda, argümanının veri tipini, sayısala çevirir ve işaretini değiştirir. Argüman sayısala çevrilemezse NaN (Not A Number) değerini döndürür.

Arttırma ve eksiltme işlemcileri, işlemciler tablosunda görüldüğü gibi,

olarak iki tanedir.

Tekli arttırma/eksiltme işlemcisi, işlenenin bulunduğu yere göre,

şeklinde kullanılabilir.

Arttırma veya eksiltme işlemcilerinin işlenenleri sayısal veya sayısal çevrilebilen bir karakter dizgisi olmalıdır. Sayısala çevrilebilen bir karakter dizgisi kavramı JavaScript programlama diline özgü, JavaScript yorumlayıcısının üstün uyarlama yeteneğinden yararlanan bir programlama kolaylığıdır. JavaScript yorumlayıcısı, karakter dizigisi literalleri iki türlü nitelendirir:

Sayısala çevrilebilir karakter dizgileri, tekli arttırma/ eksiltme işlemcilerinin işlenenleri olduklarında JavaScript yorumlayıcısı bunları otomatik olarak sayısal değerlerine dönüştürür ve arttırma veya eksiltme işlemlerini yapar. Sayıya dönüşebilen bir sözel veriye arttırma/ eksiltme işlemcilerinin uygulanması sonucunda, gerçekleşen veri tipi dönüşümü, değişkenin kopyası değil, gerçek değeri üzerinden gerçekleştirilir. Veri tipi tipi dönüşümü, geri dönülemez (irreversibl) ve tahrip edici (destrüktif) bir işlemdir. Orijinal veri tipine ancak kullanıcının yeniden açık tip veri tipi dönüştürümü yapması ile dönülebilir.

Arttırma veya eksiltme işlemcileri ile işlenenleri arasına satırbaşı karakteri konulmamalıdır. Aksi halde, JavaScript yorumlayıcısı otomatik olarak işlem sonu işlemcisi ; ekleyerek ifadeyi yanlış yorumlar.

Sadece Bir Tek Arttırma ve Eksiltme İşlemcisi İçeren İfadeler

Sadece arttırma veya eksiltme işlemcileri içeren ifadelerde, arttırma/eksiltme işlemcileri, aşağıda görüldüğü gibi önek,

++x; (önek arttırma)--x; (önek eksiltme)
		

veya sonek,

x++; (sonek arttırma)x--; (sonek eksiltme)
		

şeklinde kulllanılır. Eşdeğer ifadeler,

x=x+1; veya ,x=x-1;
		

ifadeleridir. Tek başlarına kullanıldıkları ifadelerde arttırma/eksiltme işlemcilerinin, önek veya sonek olarak kullanılmaları sonucu etkilemez. Bu ifadelerde işlenenin değeri bir artar veya bir azalır. Arrtırma/ eksiltme işlemcilerinin tek başlarına kullanıldıkları profesyonel uygulamalarda çoğunlukla sonek formları kullanılmaktadır.

Arttırma işlemcilerinin çalışmasını gösteren bir uygulamanın JavaScript kodları aşağıda görülmektedir :

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var x = 2, y = 11;
			
x++;

bilgiYaz(x, 'b2.7.2.3-uyg-1-sonuç-1');

--y;

bilgiYaz(y, 'b2.7.2.3-uyg-1-sonuç-2');

}

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

/* ]]> */
		

Sonuç : x değeri : y değeri :

Yukarıdaki uygulamanın sonuçlarından da görüldüğü gübi, tekli işlemlerin tek başına uygulandıkları ifadelerin sonuçlarına önek veya sonek şeklinde kullanımları etki yapmamaktadır. Bu ifadelerde, kullanıcılar istedikleri formu serbestçe seçebilirler.

Arttırma/eksiltme işlemcilerinin, sayısala çevrilebilen sözel bir veriye uygulanması ile veri tipinin ve değerinin kalıcı olarak değişeceği, aşağıda, JavaScript kodları verilen bir uygulamada görülmektedir.

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var w = '22.14';
w++;

veriTipiYaz(w, 'b2.7.2.3-uyg-2-sonuç-1');
}

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

/* ]]> */
		

Sonuç :

Uygulama sonuçlarından, sayısala çevrilebilen w değişkeninine, arttırma işlemcisinin uygulanması ile, w değişkenin değeri bir artmakta ve veri tipi kalıcı olarak sayısala dönüşmektedir. Arttırma/eksiltme işlemcilerinin bu yeteneğinden sayısla dönüştürülebilen sözel verilerin sayısal tipe dönüştürülmesi için yararlanılması, paragraf 2.7.3.1 uygulama 3 de yapılmıştır.

Aynı işlemin,

w = '44xAB';
++w;
		

ifadesi ile çalıştırılmak istenmesi, değer sayısala uyarlanamadığından NaN (Not a Number) değeri döndürülür..

Sadece Bir Tek Arttırma ve Eksiltme İşlemcisi İçeren İfadeler, daha çok döngü sayacının otomatik olarak arttırma/eksiltme mekanizması olmayan while dongüsü gibi döngü yapılanmalarında, döngü indisinin arttırılması için bir yazılım kolaylığı olarak düşünülmüştür. Bu işlemcilerin karmaşık ifadelerde kullanılması doğru değildir. Yine de bu işlemciler, istendiğinde, karmaşık ifadelerde kullanılabilirler, fakat bu durumlarda, işlemcinin önek veya sonek olarak kullanılması sonuçları dramatik olarak etkiler.

Arttırma ve Eksiltme İşlemcileri Yanında Başka İşlemciler de İçeren İfadeler

Tekli arttırma/eksiltme işlemcileri yanında başka işlemciler de içeren ifadeler, sonuçları kolayca öngörülebilen basit ifadeler olmaktan çıkarlar. Bu ifadelerde, arttırma/eksiltme işlemcilerinin önek veya sonek olarak kullanılması, sonuçları kesinlikle değiştirir. Bu gibi sonuçları kolayca öngörülemeyen ifadelerde çok dikkatli olmak gerekir. Öncelikle dikkat edilecek konu, bu ifadelerde, ifade sonucu ve arttırma işleminin sonucunun farklı olabileceğidir. Her zaman geçerli olan kural:

Önek : önce arttırma sonra hesaplama

Sonek : önce hesaplama sonra arttırma

olarak ifade edilebilir.

Bu kurala göre, arttırma/eksiltme işlemcisinin önek olarak kullanılması durumunda, önce değişkenin arttırımı/eksiltmesi yapılır, sonra arttırılmış veya eksiltilmiş değerin kullanılması ile, ifadenin değeri hesaplanır. Arttırma/eksiltme işlemcisinin sonek olarak kullanılması durumunda ise , önce ifadenin değerinin hesaplanması, değişkenin arttırılmamış veya eksiltilmemiş orijinal değeri ile yapılır. Sonra değişkene arttırma veya eksiltme işlemcisi uygulanarak değeri ve gerekirse veri tipi değiştirilir.

Örnek, bir uygulamanın, kodları, aşağıda görülmektedir :

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var sh = 3;

bilgiYaz(++sh * 5, 'b2.7.2.3-uyg-3-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

Yukarıdaki kodlarda, sh değişkeni üzerine önek bir arttırma işlemcisi uygulanmaktadır. Genel kurala göre, önek durumunda, öncelikle değişkenin değeri arttırılacak ve sh değişkeninin değeri (3+1 = 4) olacaktır. Bundan sonra, ifadenin hesaplanması (4 * 5 = 20) gerçekleşmekte ve sonuç 20 olmaktadır. Oysa, kodları aşağıda görülmekte olan uygulamada sonuç farklı olarak gerçekleşecektir:

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var sh = 3;

bilgiYaz(sh++ * 5, 'b2.7.2.3-uyg-4-sonuç-1');

}

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

/* ]]> */

Sonuç :

Bu ifadenin sonucu 15 olarak gerçekleşmektedir, çünkü sonek durumunda önce bellekteki orijinal değerle ifadenin sonucu hesaplanır (3 *5 = 15). Sonra arttırım gerçekleşerek sh değişkeninin değeri 1 artar (Post Expressional Incrementing).

Aslında, biraz çapraşık ve sonucunun öngörülmesi için gerekli formülün her zaman hatırda tutulması zor olan bu gibi ifadeler yerine,

sh = 3;
(sh + 1) * 5;
sh++;
		

kullanılsa, ifadenin sonucunun 20 olacağı kolaylıkla görülür. İfadenin hesaplanmasından sonra sh değişkeninin değerinin 1 artacağı önceden görülebilir. Böylelikle işlem sonucu kolaylıkla öngörülebilir hale dönüşür. Bu şekilde programın sonradan bakımı aşamasında programcılara büyük kolaylık sağlanmış olacaktır.

Aşğıda kodları görülen uygulamada, arttırma eksiltme işlemcileri ile birlikte atama işlemcisi de kullanılmaktadır:

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var s = 3;
var q = ++s + 2;

bilgiYaz(q, 'b2.7.2.3-uyg-5-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

İlk bakışta karışık görülmesine karşın, bu ifade çok basittir. Bilgisayar programlamasında, ifadeler "divide and conquer" (böl ve kazan) yöntemi ile çözülür. İlk olarak öncelikler tablosundan ifadedeki işlemcilerin öncelik sıraları saptanacaktır. Burada ilk öncelik sırası arttırma işlemcisinde, sonra toplama en son olarak atama işlemcisindedir. Burada arttırma işlemcisi, önek olarak uygulanıyor. Önek olarak uygulanan arttırma/eksiltme işlemcilerinde, işlenenin arttırımı derhal gerçekleşir. Arttırma işlemi gerçekleşir ve s=4 olur. Bundan sonra, toplama işlemi yapılır. Toplama işlemi sonunda s değişkeninin değeri, 4+2=6 olur. En sonunda, en düşük öncelikli işlemci olan atama işlemcisi işleme konulur. Bu şekilde işlem sonunda, q=6 değerini alır.

Aynı ifadenin sonekli şeklini içeren bir başka uygulamanın, JavaScript kodları, aşağıda görülmektedir:

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var s = 3;
var q = s++ + 2;

bilgiYaz(q, 'b2.7.2.3-uyg-6-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

Elde edilen sonucun 5 olması gayet doğaldır. Bu sonucun nedeni incelendiğinde, öncelikler tablosundan en yüksek önceliğin arttırma işleminde olduğu görülebilir. Ne var ki ifadelerde, sonek olarak uygulanan arttırma işlemlerinde, değişkenin değer attırımı, ifade sonunda gerçekleşir (post assignment incrementing). Bu durumda, s değişkeninin değer attırımı atama sonunda gerçekleşecektir. Toplama 3+2=5 değerini verecek ve atama sonunda q değişkenin değeri 5 olacaktır. Atama tamamlanınca, s değişkenin değer artımı gerçekleşecek ve s değişkeninin değeri 4 olacaktır.

Bazı rekürsif atama (kendi kendini çağıran atama) işlemlerinin sonuçlarının öngörülmesi iyice yanıltıcı olabilir. Böyle bir örneğin, JavaScript kodları, aşağıda görülmektedir.

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var s = 3;
s = ++s + 2;

bilgiYaz(s, 'b2.7.2.3-uyg-7-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

Bu ifade sonunda, s değeri 6 olmaktadır. Çünkü önek durumunda önce arttırma (s = 3 + 1 = 4), sonra ifadenin hesaplaması (s + 2 = 6) ve en son olarak da atama (s = 6) yapılmaktadır (önek = önce arttırma).

Aynı ifadede sonek şeklinde arttırma işlemcisinin kullanıldığı bir başka örneğin, JavaScript kodları, aşağıda görülmektedir.

/* <![CDATA[  */

/* Bu Program bdelib.js Kitaplık Programını Kullanmaktadır */

function başlat() {

var s = 3;
s = s++ + 2;

bilgiYaz(s, 'b2.7.2.3-uyg-8-sonuç-1');

}

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

/* ]]> */
		

Sonuç :

Bu ifade sonunda, s değeri 5 olmaktadır. Çünkü sonek durumunda önce ifadenin hesaplaması (s + 2 = 5) sonra atama (s = 5) yapılmaktadır (sonek = sonra arttırma). İşlem sonunda arttırma işlemcisi, işlevsiz kalmaktadır. Bu ifade bir çelişkidir ve JavaScript yorumlayıcısı bu çelişkiden çıkmak için, kendine verilen algoritmanın sadece s = s + 2; kısmını gerçekleştirerek algoritmayı sonlandırmıştır. Rekürsif atama işlemlerinde sonek arttırma/ eksiltme işlemcisinin kullanılmaması gerekir.

Bu örneklerde de görüldüğü gibi, ön ve son ekle kullanım ile gerçekleştirilen atamalar farklı sonuç vermektedir. Bu örnekler bir tür yol haritası gibi saklanarak kontrol amacı ile kullanılabilir.

Yukarıdaki örneklerden de görüldüğü gibi, tekli işlemciler, izlenmesi zor algoritmalar oluşturabilirler ve bunları iyi kullanmayı bilmeyen bir programcının hata yapması olasılığı yüksektir. Aslında, algoritmalarda bu gibi yanlış değerlendirilebilecek algoritmalar kullanılmamalıdır. Yine de profesyonel programlarda, atamalarda çoğunlukla bu işlemciler kullanılmakta olduğundan, bu sayfadaki örnekler iyi özümsenmelidir.

Kolay hatırda tutma :

Önek : önce arttırma sonra hesaplama sonra atama

Sonek : önce hesaplama sonra atama sonra arttırma

void İşlemcisi,işleneni değerlendirir, fakat geriye bir değer döndürmez. Kullanımı,

void geçerli bir JavaScript ifadesi

şeklindedir. void İşlemcisi genel olarak bir ifade sonucunu programın geri kalan adımlarından gizlemek için kullanılır. void İşlemcisinin, işleneninin parantez içine alınması zorunlu değilse de, parantez kullanımı iyi bir programlama stili sayılmaktadır.

void İşlemcisinin bir uygulama örneğinin, JavaScript kodları aşağıda görülmektedir:

...

var jx = 45;

sonuçYaz('void Değişkenin Değeri : ', void (jx), 'b2.7.2.4-uyg-1-sonuç-1');
			
...
		

Programın çıktısından da görüldüğü gibi, void işlemcisi, işlediği ifadenin (burada tek bir jx değişkeni) değerini döndürmediği için, program jx değişkenini tanımamış ve bu nedenle değerini undefined olarak belirtmiştir. jx Değişkeninin değerinin programdaki geçerli değeri değişmemiş ve istendiğinde erişilebilir halde program belleğinde kalmıştır. Yukarıdaki örnekte kullanılan, veriYaz() fonksiyonu, bdelib fonksiyon kitaplığında bulunmaktadır.

void İşlemcisinin en çok kullanıldığı uygulamalardan biri JavaScript pseudoprotokoludur. Bu konudaki açıklamalar, 1.1.3 den yeniden okunabilir..

Valid XHTML 1.1