Merhaba! Biraz yoğun olduğumdan ikinci bölüm gecikti. Serinin ilk bölümüne gitmek için bağlantıyı takip edebilirsiniz. İlk bölümden başlamak isterseniz, bağlantıyı takip edebilirsiniz. Daha fazla gecikmeden başlayalım.
Diziler, sıralı elemanlardan oluşan veri gruplarıdır. JS'teyse diziler, herhangi türlerden değerlerin (veri) bulunabildiği veri tipidir. Diziler köşeli parantez içinde yazılır ve elemanlarının arasına virgül konur. Örneğin:
meyveler adlı diziye birkaç string, yani metin değeri atadık. Peki ya bunların arasından üçüncüsünü elde edip konsola yazdırmak istersek ne yapmalıyız?
Eğer dikkatli baktıysanız, bu satır biraz abes gelebilir. Evet, mantık basit: Önce dizinin ismini, ardından da köşeli parantez içinde istediğimiz elemanın indeksini (sıra) yazıyoruz. İyi de, neden üçüncü elemanı almak için 3 değil de 2 yazdık? Bu, bilgisayarların sayma yönteminden kaynaklanıyor. Bilgisayarlar saymaya sıfırdan (0) başlarlar. Bu yüzden şu an okumakta olduğunuz 1 numaralı yazı, aslında serinin ikinci yazısı. Yine bu yüzden -inşallah- sitenin 11. yazısı olacak olan bu yazı, kaynak kodlarımızda 10 numaralı. O halde yukarıdaki iki satırı çalıştırdığınızda çıktı olarak frambuaz almalısınız.
İki dizinin aynı olup olmadığına nasıl karar veririz? Önceki yazıdan hatırlarsak karşılaştırma operatörlerinden olan eşittir (==) ve denktir (===) bu konuda işimizi görüyordu. Ancak JS kodumuzda içerikleri birbiriyle tıpa tıp aynı iki dizi oluşturup bunları karşılaştırdığımızda beklenmedik bir çıktıyla karşılaşırız:
İki taraftaki değerler eşit olduğunda true, yanlış olduğunda false döndüren bu operatör burada false döndürdü! Bunun sebebi JS'te dizilerin değerlerine göre değil, bellekteki adreslerine göre karşılaştırılmasıdır. İki dizi tamamen aynı olsalar bile bellekte farklı konumlarda tutulmaktadırlar. Ancak aynı kodu şöyle yazsaydık beklediğimiz sonucu alırdık:
var dizi2 = dizi1; // "dizi2", "dizi1"in kopyası değil, ona doğrudan bir referans.
console.log(dizi1 == dizi2); // "true" döndürür. adresler aynı.
Peki ya iki ayrı değişkene atanmış iki diziyi nasıl karşılaştırabiliriz? İşte burada en akla yatkın yöntem bu dizileri -ki JSON tipi verilerdir- metne çevirmek. Bunun içinse JSON.stringify() fonksiyonunu kullanıyoruz. Bu fonksiyon tek bir parametre alıyor: Metne çevrilecek JSON verisi (örn. dizi, nesne). Deneyelim:
var dizi2 = [1, true, "selam"];
console.log(JSON.stringify(dizi1) == JSON.stringify(dizi2)); // "true" döndürür. iki dizi gerçekten de eşitmiş...
JS'te değişkenlerin veri tiplerindene göre nitelikleri (property) ve metotları (method) vardır.
Nitelikler, o değişkene ait özelliklerdir. Örnek olarak diziler için dizinin uzunluğunu veren length özelliği verilebilir. Zaten dizilerin kendilerine özel olan tek niteliği de budur.
Metotlar ise o değişkenin üzerinden çağrılabilen, yine bir değer döndüren fonksiyonlardır. Fonksiyon olduklarından niteliklerden farklı olarak parametre alabilirler, yani içlerine girilen değere göre verdikleri sonuç değişebilir. Örneklerle daha iyi anlayabiliriz:
dizi.nitelik; // Diziye ait bir nitelik.
dizi.metot(); // Diziye ait bir metot.
dizi.metot(3, "test"); // Metodun içine iki parametre girilmiş.
Bu kod bir hata verecektir, çünkü dizilerin ne nitelik adında bir niteliği ne de metot isminde bir metodu var. Aslen tanımlı olmayan bir niteliği kodunuzda kullanmanız hata oluşturmaz, yalnızca o niteliğin değeri undefined (tanımsız) olur. Ancak tanımlı olmayan bir metodu çağırmak hata verecektir. Şimdi gelin, dizilerin sık kullanılan nitelik ve metotlarına bir bakalım:
Yukarıdaki gibi bir dizimiz olsun:
console.log(notlar.length); // "5" yazdırır.
console.log(notlar); // İlk diziyi yazdırır.
notlar.push(100); // Dizinin sonuna "100" eklendi.
console.log(notlar); // Sonuna "100" eklenmiş diziyi yazdırır.
console.log(notlar); // İlk diziyi yazdırır.
notlar.pop(); // Dizinin son elemanı çıkarıldı (94).
console.log(notlar); // "94"süz diziyi yazdırır.
// NOT: pop() metodu son elemanı çıkarırken değer olarak o elemanı döndürür. Yani "console.log([1, 2, 3].pop());" gibi bir kod, ekrana "3" yazdırır. Bu mantık, diğer benzer metotlarda da işler.
console.log(notlar); // İlk diziyi yazdırır.
notlar.shift(); // Dizinin ilk elemanı çıkarıldı (68).
console.log(notlar); // "68"siz diziyi yazdırır.
console.log(notlar); // İlk diziyi yazdırır.
notlar.unshift(62); // Dizinin başına "62" eklendi.
console.log(notlar); // Başına "62" eklenmiş diziyi yazdırır.
console.log(notlar); // İlk diziyi yazdırır.
notlar.reverse(); // Dizi ters çevrildi.
console.log(notlar); // Ters çevrilmiş diziyi yazdırır.
var diller = ["Türkçe", "İngilizce", "Fransızca", "Arapça"];
console.log(diller); // İlk diziyi yazdırır.
diller.sort(); // Dizi ters çevrildi.
console.log(diller); // Ters çevrilmiş diziyi yazdırır.
// NOT: Bu metot, sayı içerikli dizileri sıralamak için kullanılmaz çünkü alfabetik sıraya göre sıralar. Sayı sıralaması için karşılaştırma operatörleri kullanılmalıdır.
console.log(notlar); // İlk diziyi yazdırır.
notlar = notlar.map(n => n + 10); // Hoca herkese onar puan ekledi.
console.log(notlar); // Ters çevrilmiş diziyi yazdırır.
// NOT: Bu metot, uygulandığı diziyi değiştirmez. Değiştirilmiş diziyi yalnızca değer olarak döndürür. Bu yüzden dizi, dizinin metot uygulanmış haline eşitlenmelidir. Bu mantık, sonraki 3 metot için de geçerlidir.
console.log(notlar); // İlk diziyi yazdırır.
notlar = notlar.filter(n => n >= 85); // Notu 5 olan öğrenciler.
console.log(notlar); // Açıklamaya gerek yok.
console.log(notlar); // İlk diziyi yazdırır.
notlar = notlar.slice(1, 3); // 2 ve 3. elemanlar (0'dan başlanır :o)
console.log(notlar);
console.log(notlar); // İlk diziyi yazdırır.
notlar = notlar.concat([98, 96]); // 2 yeni öğrenci geldi. Notları da bayağı iyi.
console.log(notlar);
Şu ana kadar diziyi değiştiren veya dizinin değiştirilmiş halini döndüren metotlara baktık. Biliyorum, buralar ezber. Ama fazla büyütmeyin, kullana kullana ezberlenecek şeyler. Şimdiyse birkaç tane "kontrol metodu"na bakacağız. Yani bu metotlar diziyi değiştirmiyor, dizinin içinde bir şey kontrol ediyor veya bir şey buluyor.
console.log(notlar.includes(82)); // "true" yazdırır, dizide "82" var.
console.log(notlar.includes(83)); // "false" yazdırır, dizide "83" yok.
console.log(notlar.indexOf(82)); // "1" yazdırır, dizinin 1 numaralı (2.) elemanı "82".
console.log(notlar.includes(83)); // "-1" yazdırır, dizide "83" yok.
console.log(notlar.find(n => n >= 85)); // Notu 5 olan ilk öğrencinin puanını (90) döndürür.
console.log(notlar.find(n => n >= 100)); // 100'ün üzerinde alan öğrenci yok. "undefined" döndürür.
console.log(notlar.findIndex(n => n >= 85)); // Notu 5 olan ilk öğrencinin dizideki sırasını (3) döndürür.
console.log(notlar.findIndex(n => n >= 100)); // 100'ün üzerinde alan öğrenci yok. "-1" döndürür.
console.log(notlar.some(n => n >= 85)); // Notu 5 olan iki öğrenci var. "true" döndürür.
console.log(notlar.every(n => n >= 85)); // Notu 5 olmayan öğrenciler de var. "false" döndürür.
Ve son olarak...
console.log(notlar.join(", ")); // Aralarına virgülle notları yazdırır.
Her ne kadar çok tercih edilmese de dizileri alternatif olarak "constructor" ile de oluşturabiliriz. Bu kavramın ne anlama geldiğini inşallah sonraki yazıda öğreneceğiz.
var dizi2 = new Array(1, 2, 3); // Constructor (yapıcı) ile oluşturulmuş dizi.
Diziler bu kadardı. Şimdi sıra koşullu önermelerde!
Koşullu önermeler, bir ifadenin doğruluğuna bağlı olarak çalışan kod bloklarıdır. Bu yazıda bunlardan if-else, while, switch ve ternary operatörünü öğreneceğiz. İlkinden başlayalım:
Bu ifadelerin temel yapısı şu şekildedir:
// "koşul" doğruysa çalışacak kod.
}
else if (koşul2) {
// "koşul" yanlış ama "koşul2" doğruysa çalışacak kod.
}
else {
// Zincirdeki tüm koşullar yanlışsa çalışacak kod.
}
Alt alta istediğiniz kadar else if ekleyebilirsiniz, yeter ki bunlar if ile else'in arasında olsun. Birkaç örneğe bakalım:
if (sesDuzeyi < 30) {
console.log("Ses düşük.");
}
else if (sesDuzeyi < 60) {
console.log("Ses orta.");
}
else {
console.log("Ses yüksek.");
}
Gelin, bu kodu Türkçeye çevirelim:
"Öncelikle 'sesDuzeyi' adında bir sabit oluşturup değerini 15 olarak belirle. sesDuzeyi, 30'dan küçükse konsola 'Ses düşük.' yazdır. Değilse, 60'dan küçükse konsola 'Ses orta.' yazdır. O da değilse konsola 'Ses yüksek.' yazdır. Tamam."
Sonuç olarak kod, konsola "Ses düşük." yazdıracaktır. İlk koşuldan sonrasına bakmayacaktır bile. Şimdi de biraz kafa karıştırıcı bir örneğe bakalım:
var gorev = "";
if (yas < 5) {
gorev = "Oyuncak oynamak.";
yas += 20;
}
else if (yas < 18) {
gorev = "Okula gitmek.";
yas += 40;
}
else if (yas < 55) {
gorev = "İşe gitmek.";
}
console.log(gorev);
Bu kodun son satırda ekrana ne yazmasını beklersiniz? İlk bloğun çalışmayacağı aşikâr. Ancak ikinci blok çalışacak, çünkü yas, 18'den küçük. Bu durumda da gorev değişkenine yeni değeri atanacak ve yas, 40 fazlasına, yani 49'a çıkarılacak. Bu durumda son önerme de doğru olacak. Peki ya son blok çalışacak ve gorev = "İşe gitmek." mi olacak? Hayır! Çünkü else if ile başlayan bloklar, ancak bulundukları zincirde daha önceki tüm önermeler yanlışsa çalışırlar. Ama burada bir önceki önerme zaten doğruydu, yani o zincir ile işimiz bitti. Ekrana yazdırılacak metin, "Okula gitmek." olacaktır. Fakat üçüncü önermede else if yerine if anahtar kelimesini kullansaydık yeni bir zincir başlatmış olacaktık, yani o blok da çalışacaktı. Bu yüzden ekrana "İşe gitmek" yazdırılacaktı.
Hem koşullu önerme hem de döngü sayılabilecek while blokları, if bloklarına benzerler. Ancak girilen önermeyi bir sefer kontrol edip geçmek yerine sürekli kontrol eder ve önerme doğru oldukça içindeki kod çalışır. Yani bu iki ifadeyi şu şekilde Türkçeye dökebiliriz:
- If: Doğru ise çalıştır. Geç.
- While: Doğru oldukça çalıştır.
Bir örneğe bakalım, ancak bilgisayarınıza güvenmiyorsanız bu tarayıcınızı yavaşlatabilir, hatta sekmeyi kapatıp açmak zorunda kalabilirsiniz. Çünkü while döngülerini bu şekilde bekleme süresi olmadan çalıştırmak programı zorlar:
while (sayi <= 3000) {
if (sayi == 3000) {
console.log("Sayaç, 3000'e ulaştı.");
}
else {
console.log(sayi + ", 3000'den küçük.");
}
sayi++;
}
Yukarıdaki kodda while ve if-else blokları iç içe. Kod, sayi değişkeni 3000 olana kadar sürekli sayacın 3000'den küçük olduğunu söyleyecek, 3000 olduğunda ise sayacın 3000'e ulaştığını söyleyecektir. Ayrıca while döngüleri şu şekilde de kullanılabilir:
do {
console.log(i);
i--;
} while (i < 10 && i >= 0);
Kod bu şekilde yazıldığında while'dan sonra gelen önerme doğruyken do bloğundaki kod çalışır. Ancak burada önce kod çalışıp sonra önerme kontrol edildiğinden do bloğundaki kod önermenin doğruluğuna bağlı olmaksızın en az bir defa çalışır. Dolayısıyla yukarıdaki kod, başlangıçta i < 10 ifadesi yanlış olsa da çalışacak, böylelikle i, 9'a düşecek ve 10'dan 0'a kadarki tüm tamsayıları yazdıracak.
Web sayfaları genellikle senkron (eş zamanlı) çalıştığından while döngüsü pek sık kullanılmaz. Ayrıca while döngülerini bu şekilde bekleme süresi olmadan kullanmak tarayıcıyı yavaşlatabilir. Bu yüzden daha karmaşık örneklere ihtiyacımız yok, switch'e geçebiliriz.
Aslen switch, if-else'in muadilidir. Onunla yazılan her kod, if-else ile de yazılabilir. Ancak bazı durumlarda uzun if-else zincirleri kullanmaktansa switch-case kullanmak daha mantıklıdır. Örnekle görelim:
var meshurGida = "";
Diyelim ki burada sehir değişkenini birkaç şehirle karşılaştırarak o şehrin meşhur yiyeceğini meshurGida değişkenine atamak ve ekrana yazdırmak istiyoruz. Çorum ise leblebi, Amasya ise elma ve Erzurum ise kebap. Öncelikle bildiğimiz yöntemle yapalım:
if (sehir == "Çorum") {
meshurGida = "Leblebi";
}
else if (sehir == "Amasya") {
meshurGida = "Elma";
}
else if (sehir == "Erzurum") {
meshurGida = "Kebap";
}
else {
meshurGida = "Bilinmiyor";
}
console.log(meshurGida);
Şimdi ise aynı şeyi switch ile yapıp açıklayalım:
switch (sehir) {
case "Çorum":
meshurGida = "Leblebi";
break;
case "Amasya":
meshurGida = "Elma";
break;
case "Erzurum":
meshurGida = "Kebap";
break;
default:
meshurGida = "Bilinmiyor";
break;
}
console.log(meshurGida);
Bu kod da aynı işlevi görüyor, ancak daha kısa ve pratik. switch ifadesinden sonra değeri kontrol edilecek olan değişken giriliyor. Sonrasında her case ile bu değişkenin bir değere eşit olup olmadığı kontrol ediliyor, eşitse altındaki girintili kodlar çalıştırılıyor. Değişken hiçbir değerle uyuşmazsa da default'un içindeki kod çalışıyor. Bu da else'e benziyor. Unutmayın: Her case bloğunun ve default'un sonunda break anahtar kelimesi ile bloktan çıkılmalıdır, aksi takdirde sonraki satırlar da çalışmaya devam eder.
Şimdi yazının son konusu olan "Döngüler"e geçelim.
Döngüler, adı üstünde, belli koşullar altında kendini tekrar eden kod bloklarıdır. Mesela 1'den 100'e kadarki tüm sayıları ekrana yazdırmanız istendiğinde 100 defa console.log çalıştırmazsınız. İlk değeri 1 olan bir sayaç oluşturur, sonra sayacın değeri 101 olana dek onu yazdırır ve 1 artırırsınız. Yani halihazırda sayaç olarak kullanacağımız i isminde bir değişkenimiz varsa çalışacak kod yalnızca şudur:
i++;
Ancak bu kodu belli şartlarda sürekli çalıştırmalıyız. Yoksa ekrana 1 yazdırır, değişkeni 2 yapar ve işlemi bitirir. İşte tam da burada döngüleri kullanıyoruz.
Bu yazıda for ve türevleri, forEach ve setInterval'a göz atacağız. Ayrıca az önce bahsedilen while'ın da bir döngü olduğunu unutmayın.
For döngülerinin temel yapısı şöyledir:
// Tekrarlanacak ifade
}
Burada öncelikle baslatma yerine döngünün başında çalışacak kod yazılır. Buraya genellikle (%99,9) sayaç oluşturacak kod (let i = 0 veya direkt i = 0) yazılır. kosul kısmında ise döngünün hangi koşullarda tekrarlanacağı belirlenir. guncelleme kısmına girilen kod ise her adımın ardından uygulanacak olan koddur. Burada genellikle (yine %99,9) sayaç istenen miktarda artırılır veya azaltılır. Örneğin 0'dan 100'e kadar beşer beşer sayacak kodu yazalım:
console.log(i);
}
Görüldüğü üzere bu kodda öncelikle i ismiyle bir sayaç değişkeni oluşturup başlangıç değerini 0 olarak belirliyoruz. Sonra bu sayaç 100'den küçük veya 100'e eşit olduğu sürece onu konsola yazdırıp 5 artırıyoruz.
For döngüsünün iki çeşidi daha var: for ... of ve for ... in. Bunlara da göz atalım:
const isimler = ["Ahmet", "Mehmet", "Ayşe", "Fatma"];
for (const isim of isimler) {
console.log("Benim adım " + isim + "!");
}
Burada isimler dizisinin her bir elemanı (isim) için döngüyü tekrarlıyoruz. isim yerine istediğiniz ifadeyi girebilirsiniz. Kodu çalıştırdığınızda her isim için "Benim adım (...)!" yazdıracak. Burada da const yerine var veya let de kullanılabilir. Hatta hiçbir şey de kullanılmayabilir ancak "strict mode"da çalışmaz. Diğer döngümüz olan for ... in ise dizilerin elemanları için değil nesnelerin anahtarları için çalışır. Ancak henüz nesnelerden bahsetmediğimiz için onunla ilgili yalnızca kısa bir örnek göstereceğim:
const dukkan = {
isim: "Falancanın Mekan",
tur: "Kafe",
yer: "Ankara"
};
for (const key in dukkan) {
console.log(key + ": " + dukkan[key]);
}
Bu döngü aslında dizilerin metotlarından biri, ancak döngü kategorisine girdiğinden burada anlatmak istedim. Bu döngü, bazı detaylar dışında for ... of döngüsüyle aynı işlevi görür. Kısa bir örneğe bakalım:
diller.forEach(item => {
console.log(item + " öğrenmek istiyorum.");
});
Burada da aynı şekilde diller isminde bir dizi oluşturup bu dizinin tüm elemanları için konsola "(...) öğrenmek istiyorum." yazdırıyoruz. Yapısı şu an biraz karışık gelebilir, ancak sonraki yazıda bu yapının neden böyle gözüktüğünü daha rahat anlaşılacak.
Dersimizin son iki konusu: setInterval ve setTimeout. Aslında setTimeout bir döngü değil, ancak setInterval'ın kardeşi sayılabileceğinden ondan da burada bahsetmek istedim.
setInterval fonksiyonu, içine girilen kodu istenen aralıklarla çalıştırılır. Temel yapısı şu şekildedir:
// fonksiyon: Çalıştırılacak olan fonksiyon/kod öbeği.
// mola: Her çalıştırmadan sonra beklenecek süre. (ms)
Bir de gerçek bir örnek inceleyelim:
console.log("Merhaba Dünya!");
}, 1500);
Bu kod, her 1,5 saniyede bir "Merhaba Dünya!" yazdıracaktır (1s = 1000ms). Eğer çalışan bir interval'ı durdurmak istersek onu oluştururken bir değişkene atamamız gerekir. Bu sayede clearInterval(interval) fonksiyonuyla onu istediğimiz zaman iptal edebiliriz:
var tekrarliKod = setInterval(() => {
console.log(i);
i++;
if (i == 4) {
clearInterval(tekrarliKod);
}
}, 1500);
Bu kodda ise 0, 1, 2 ve 3 sayıları yazdırıldıktan sonra interval durdurulacak. Çünkü 3 sayısı yazdırılıp i 4'e çıkarıldığında if'in içindeki önerme doğru olacak ve clearInterval fonksiyonu çalışacak.
setTimeout'un da yapısı benzerdir. Ancak setTimeout bir döngü değildir, yani içine girilen kodu tekrar tekrar çalıştırmaz. İstenen süre geçtikten sonra bir defa çalıştırıp bırakır:
console.log("Bu metin, sayfa yüklendikten 1,5 saniye sonra yazdırılacak.");
}, 1500);
Interval'larda olduğu gibi burada da clearTimeout şeklinde bir fonksiyonumuz var. Örneğin 60 saniye sonra çalışacak sayac şeklinde bir timeout'umuz olduğunda bu timeout çalışmadan önce clearTimeout(sayac) koduyla onu iptal edebiliriz.
Bu yazı için bu kadarı yeterli sanırım, devamı sonrakine inşallah. Yardımcı olabilmişimdir umarım. Fındıklı Bilgiler, iyi günler diler :)
Yorumlar ()