İçeriğe geç
XDD.baby Yazılım Öğrenme
Sözlük Hata rehberi 0/56

Blok 2 · Ders 9

Metinler ve sayılarla çalışmak

Şablon metinler, metin metotları, sayı ile metin arasında dönüşüm ve Math ile oyun istatistiklerini düzgün biçimde gösteriyorsun.

Bu dersin sonunda

  • Şablon metin ve ${ } yuvalarıyla değişkenleri ve hesapları metnin içine yerleştirebilirsin
  • Metin metotlarıyla adları kısaltabilir, sohbet mesajlarını denetleyebilir, metni parçalara bölebilir ve hizalı tablolar yazdırabilirsin
  • Türkçe harfleri toLocaleUpperCase ve toLocaleLowerCase ile doğru büyütüp küçültebilirsin
  • Metni sayıya, sayıyı metne çevirebilir; NaN değerini Number.isNaN ile yakalayabilirsin
  • Math ile yuvarlayıp sınırlayabilir, 0.1 + 0.2 tuzağına düşmeden karşılaştırabilirsin
  • Bir maç geçmişinden KDA ve kazanma oranını, sıfıra bölmeye karşı korunmuş olarak hesaplayıp gösterebilirsin
Bu sayfada
  1. Şablon metin: artı zincirine son
  2. Metin metotları: metne iş yaptırmak
  3. Türkçe harf tuzağı: i ile İ
  4. Metinden sayıya, sayıdan metne
  5. NaN: sayı olmayan sayı
  6. Math ile yuvarlamak ve sınırlamak
  7. Ondalık tuzağı: 0.1 + 0.2
  8. Uygulama: KDA ve kazanma oranı
  9. Sık hatalar
  10. Görevler
  11. Kendini sına
  12. Kayıt noktası

Şimdiye kadar oyun verileriyle hesap yaptın ama sonuçları ekrana pek düzgün yazdıramadın: + ile uzayan satırlar, 3.3333333333333335 gibi bitmeyen sayılar, büyük-küçük harf yüzünden tutmayan karşılaştırmalar. Bu derste metinleri ve sayıları istediğin biçime sokmayı öğreniyorsun. Sonunda bir maç geçmişini okuyup her maçın KDA'sını ve kazanma oranını hizalı bir tabloyla gösteren bir program yazacaksın.

Şablon metin: artı zincirine son

Ahri'nin maç skorunu Ders 1'den bildiğin yolla, + ile yazdır:

ders9.js
const isim = "Ahri"const kill = 7const olum = 2const asist = 9console.log(isim + " " + kill + "/" + olum + "/" + asist)
Çıktı
Ahri 7/2/9

Çalışıyor ama okuması zor: tırnak aç, kapat, artı, yine tırnak… Bir boşluğu unutmak ya da bir tırnağı yanlış yere koymak işten bile değil. Aynı satırı şablon metin ile yaz:

ders9.js
const isim = "Ahri"const kill = 7const olum = 2const asist = 9console.log(`${isim} ${kill}/${olum}/${asist}`)
Çıktı
Ahri 7/2/9

Metin çift tırnakla değil, ters tırnakla açılıp kapanıyor ve değişkenler metnin içine ${ } ile yerleşiyor. JavaScript ${isim} gördüğü yerde isim kutusunun içindekini yazar. Çıktı aynı, ama kod artık çıktının neye benzeyeceğini gösteriyor: boşluklar ve eğik çizgiler tam yerinde.

ters tırnak: şablonu açar ve kapatır `${isim} ${kill} kill aldı` yuva yuva düz metin isim kutusu "Ahri" kill kutusu 7 olduğu gibi kalır sonuç Ahri 7 kill aldı
Şekil 9.1 Şablon metnin parçaları. Ters tırnaklar şablonu açıp kapatır, ${ } yuvalarına değerler yerleşir, gerisi olduğu gibi kalır.

Ters tırnak nasıl yazılır?

Ders 0'daki klavye tablosunda gördün: Türkçe Q klavyede ters tırnak AltGr + , ile yazılır. Virgül tuşu orta sıranın en sağında, İ'nin yanında ve Enter'ın hemen solundadır. AltGr, boşluk çubuğunun sağındaki Alt tuşudur.

Bu tuş bir ölü tuştur (dead key): basınca ekranda hemen bir şey çıkmaz, Windows bir sonraki tuşu bekler. Ardından Boşluk'a basınca ` belirir. Bu işareti Ders 7'de README'deki kod bloklarını yazarken de kullanmıştın.

O P Ğ Ü Enter L Ş İ ;,` Ö Ç . Shift Boşluk AltGr Ctrl Ters tırnak nasıl yazılır? 1 AltGr'yi basılı tut, virgül tuşuna bas. Ekranda henüz bir şey çıkmaz. 2 Boşluk'a bas: ` belirir. Boşluk yerine a, e, ı, i, o, u yazarsan à, è, ì, ò, ù gibi harfler çıkar.
Şekil 9.2 Türkçe Q klavyede ters tırnak: önce AltGr + ,, sonra Boşluk.

Yuvaya hesap da yazılır

${ } yuvasının içine sonucu bir değer olan her şeyi yazabilirsin: değişken, obje alanı (Ders 4), dizi elemanı (Ders 5), hesap ya da değer döndüren bir fonksiyon çağrısı (Ders 6). JavaScript önce yuvanın içini hesaplar, sonucu metne çevirip oraya koyar:

ders9.js
const ahri = { isim: "Ahri", hp: 640, maxHp: 800 }console.log(`${ahri.isim}: ${ahri.hp}/${ahri.maxHp} can`)console.log(`Can yüzdesi: ${ahri.hp / ahri.maxHp * 100}`)console.log(`Yarısı: ${ahri.maxHp / 2}`)
Çıktı
Ahri: 640/800 canCan yüzdesi: 80Yarısı: 400

Şablon metnin içinde çift tırnak da serbesttir: `"${isim}" bulunamadı` yazabilirsin. Çift tırnaklı bir metnin içine çift tırnak koymaya kalksaydın metin erken kapanırdı.

Çok satırlı metin

Çift tırnaklı metin aynı satırda bitmek zorundadır. Ters tırnaklı metin ise birden çok satıra yayılabilir; satır sonları da metnin parçası olur:

ders9.js — ogren — Visual Studio Code
ders9.js
const isim = "Lux"const seviye = 11const kart = `Şampiyon: ${isim}Seviye: ${seviye}Durum: hazır`console.log(kart)
PROBLEMSOUTPUTDEBUG CONSOLETERMINAL
PS C:\kod\ogren> node ders9.jsŞampiyon: LuxSeviye: 11Durum: hazır
Ln 1, Col 1Spaces: 4UTF-8JavaScript

Şablon metin 3. satırda açılıp 5. satırda kapanıyor. Arada bastığın her Enter çıktıda yeni bir satır oldu.

Yuva yalnızca ters tırnakta çalışır

JavaScript✗ Yanlış
console.log("KDA: ${kda}")
JavaScript✓ Doğru
console.log(`KDA: ${kda}`)

Çift ya da tek tırnak içindeki ${kda} sıradan bir yazıdır: ekrana harfi harfine basılır ve hata mesajı çıkmadığı için gözden kaçar. Ters tırnağı ona benzeyen kesme işaretiyle (') karıştırırsan da yuva çalışmaz.

Metin metotları: metne iş yaptırmak

Ders 5'te diziye takim.push("Lux") ile eleman ekledin; değerin arkasına nokta koyup bir metot çağırdın. Metinlerin de hazır metotları var: büyük harfe çevirmek, içinde aramak, parçalara bölmek, boşluk temizlemek… Hepsi aynı kalıpla yazılır: metin.metotAdi(…); parantezin içine metodun argümanları gelir.

Önemli bir fark var: push dizinin kendisini değiştiriyordu, metin metotları ise metne dokunmaz. Büyütülmüş, kırpılmış ya da değiştirilmiş hâlini yeni bir metin olarak döndürürler. Sonucu kullanmak istiyorsan ya yazdırırsın ya da bir kutuya koyarsın:

ders9.js
let mesaj = "gg wp"mesaj.toUpperCase()console.log(mesaj)mesaj = mesaj.toUpperCase()console.log(mesaj)
Çıktı
gg wpGG WP

İkinci satır büyük harfli yeni metni üretti ama hiçbir yere koymadı; Ders 1'deki "hesaplamak yetmez, koymak gerekir" tuzağının aynısı. Dördüncü satır sonucu mesaj kutusuna geri koyduğu için değişiklik kaldı.

length: kaç karakter?

ders9.js
const yer = "Sihirdar Vadisi"console.log(yer.length)console.log(yer[0])console.log(yer[yer.length - 1])
Çıktı
15Si

length boşluk dahil karakter sayısını verir. Metin, harflerden oluşan bir dizi gibidir: her karakterin 0'dan başlayan bir sıra numarası vardır ve son karakter length - 1 numaradadır. Dizilerdeki gibi length bir metot değil, bir alandır; sonuna parantez koyarsan TypeError: yer.length is not a function alırsın.

toUpperCase ve toLowerCase: büyük-küçük harf

Ders 2'den biliyorsun: "TEEMO" ile "Teemo" JavaScript için iki ayrı metindir. Oyuncunun nasıl yazdığını bilemezsin; karşılaştırmadan önce iki tarafı da aynı biçime getir:

ders9.js
const yazilan = "TEEMO"console.log(yazilan.toLowerCase())console.log(yazilan === "Teemo")console.log(yazilan.toLowerCase() === "teemo")
Çıktı
teemofalsetrue

toUpperCase() bütün harfleri büyütür, toLowerCase() küçültür. İkisi de argüman almaz ama parantezleri şarttır. Türkçe harflerde bu iki metodun bir tuzağı var; ona ayrı bir bölüm ayırdık.

includes ve startsWith: sohbet filtresi

ders9.js
const mesaj = "Bu Teemo tam bir NOOB"console.log(mesaj.includes("Teemo"))console.log(mesaj.includes("noob"))console.log(mesaj.toLowerCase().includes("noob"))
Çıktı
truefalsetrue

includes, aradığın parça metnin herhangi bir yerinde geçiyorsa true, geçmiyorsa false döndürür; Ders 5'te dizilerde kullandığın includes'un metin hâli. Büyük-küçük harfe duyarlıdır, bu yüzden ikinci satır false.

Üçüncü satırda iki metot art arda çalıştı: önce toLowerCase() küçük harfli yeni bir metin üretti, includes o yeni metnin üstünde çalıştı. Buna zincirleme denir. Dizilerle Ders 11'de çok daha uzun zincirler kuracaksın.

startsWith ise yalnızca metnin başına bakar. Sohbette / ile başlayan mesajlar komuttur:

ders9.js
const mesaj = "/mute Teemo"if (mesaj.startsWith("/mute ")) {    console.log("Susturma komutu")} else {    console.log("Normal mesaj")}
Çıktı
Susturma komutu

slice: bir parçayı kesip almak

slice(baslangic, bitis) metnin bir parçasını kopyalar: başlangıçtaki karakter dahil, bitişteki hariç. Akılda tutmanın iyi bir yolu, numaraları harflerin üstüne değil aralarına çizilmiş kesim çizgileri gibi düşünmek. slice(1, 3) "1 numaralı çizgiden kes, 3 numaralı çizgiye kadar al" demektir:

sıra no 0 1 2 3 4 G a r e n length: 5 kesim 0 1 2 3 4 5 slice(1, 3) → "ar" 1. çizgiden başla, 3. çizgide dur
Şekil 9.3 "Garen".slice(1, 3): 1 ve 3 numaralı kesim çizgileri arasındaki harfler alınır. Başlangıç dahil, bitiş hariç.
ders9.js
const isim = "Garen"console.log(isim.slice(0, 3))console.log(isim.slice(1, 3))console.log(isim.slice(2))console.log(isim.slice(-2))console.log(isim.slice(0, 99))
Çıktı
GararrenenGaren
  • slice(0, 3): 0 ile 3 numaralı çizgiler arası, yani ilk üç harf.
  • Tek argüman verirsen sona kadar gider: slice(2).
  • Eksi sayı sondan sayar: slice(-2) son iki harf.
  • Sınırın ötesine taşarsan hata çıkmaz, elinde ne varsa o gelir: slice(0, 99).

startsWith ile birlikte kullanınca komutun hedefini ayıklayabilirsin. "/mute " altı karakterdir (eğik çizgi, dört harf, boşluk), bu yüzden hedef 6 numaralı çizgiden başlar:

ders9.js
const mesaj = "/mute Teemo"if (mesaj.startsWith("/mute ")) {    const hedef = mesaj.slice(6)    console.log(`${hedef} susturuldu`)}
Çıktı
Teemo susturuldu

split: metni diziye bölmek

ders9.js
const takimMetni = "Ahri,Lux,Garen"const takim = takimMetni.split(",")console.log(takim)console.log(takim.length)for (const sampiyon of takim) {    console.log(`- ${sampiyon}`)}
Çıktı
[ 'Ahri', 'Lux', 'Garen' ]3- Ahri- Lux- Garen

split(ayirici) metni ayırıcının geçtiği her yerden keser ve parçaları bir dizi olarak döndürür; ayırıcının kendisi atılır. Sonuç Ders 5'teki dizilerden farksızdır: length'i var, for...of ile gezebilirsin. Dışarıdan gelen virgüllü listeler, 7/2/9 gibi skorlar, Ad#Etiket biçimindeki oyuncu kimlikleri hep böyle parçalanır.

trim: baştaki ve sondaki boşluklar

Kullanıcının yazdığı metinler (ileride klavyeden ve formlardan alacaksın) çoğu zaman başında ya da sonunda fazladan boşlukla gelir. trim() bu boşlukları atar, aradakilere dokunmaz:

ders9.js
const girilen = "   Sihirdar Vadisi  "console.log(`[${girilen}]`)console.log(`[${girilen.trim()}]`)console.log(girilen.trim() === "Sihirdar Vadisi")
Çıktı
[   Sihirdar Vadisi  ][Sihirdar Vadisi]true

Köşeli parantezleri yalnızca boşlukları görebilmek için koyduk; terminalde boşluk görünmez.

replace ve replaceAll: değiştirmek

ders9.js
const mesaj = "noob Teemo, gerçekten noob"console.log(mesaj.replace("noob", "****"))console.log(mesaj.replaceAll("noob", "****"))
Çıktı
**** Teemo, gerçekten noob**** Teemo, gerçekten ****

replace(aranan, yeni) yalnızca ilk bulduğunu değiştirir; hepsini değiştirmek için replaceAll var. İkisi de büyük-küçük harfe duyarlıdır, yani "NOOB" yakalanmaz. Aranan parça hiç yoksa metin olduğu gibi geri gelir, hata çıkmaz.

padStart ve padEnd: hizalı tablo

Ders 8'deki skor tablonun sütunları hizasız kalmıştı: adlar farklı uzunlukta olunca arkalarındaki sayılar kayıyordu. Sütunları hizalamak için her hücreyi aynı uzunluğa getirmen gerekir. padEnd(uzunluk) metnin sonuna, padStart(uzunluk) başına boşluk ekleyerek onu o uzunluğa tamamlar. Dükkândaki eşya listesiyle dene:

ders9.js
console.log("Kılıç".padEnd(8) + "450".padStart(6))console.log("İksir".padEnd(8) + "50".padStart(6))console.log("Kalkan".padEnd(8) + "1100".padStart(6))
Çıktı
Kılıç      450İksir       50Kalkan    1100

Adlar sola, fiyatlar sağa yaslandı; sağa yaslanan sayıların basamakları alt alta gelir. İkinci argüman boşluk yerine eklenecek karakteri söyler: "7".padStart(2, "0") sonucu "07". Metin zaten o uzunluktaysa ya da daha uzunsa hiçbir şey eklenmez, metin kısaltılmaz da; sütun genişliğini en uzun değere göre seç.

padStart bir metin metodudur. Sayıda çağırırsan program durur; çözümünü Sık hatalar bölümünde göreceksin.

Bu bölümdeki metotların hepsi bir arada:

Ne yapar?ÖrnekSonuç
Uzunluk (alan)"Lux".length3
Büyük harf"gg".toUpperCase()"GG"
Küçük harf"GG".toLowerCase()"gg"
İçinde var mı?"gg wp".includes("wp")true
Bununla mı başlıyor?"/all".startsWith("/")true
Parça kopyala"Garen".slice(0, 3)"Gar"
Böl, dizi ver"7/2/9".split("/")[ '7', '2', '9' ]
Kenar boşluklarını at" Lux ".trim()"Lux"
İlkini değiştir"a-b-c".replace("-", "+")"a+b-c"
Hepsini değiştir"a-b-c".replaceAll("-", "+")"a+b+c"
Başa ekleyip tamamla"7".padStart(3, "0")"007"
Sona ekleyip tamamla"Lux".padEnd(5, ".")"Lux.."

Türkçe harf tuzağı: i ile İ

toUpperCase ve toLowerCase hangi dilde yazdığını bilmez; İngilizceye uyan, dilden bağımsız kurallarla çalışır. İngilizcede noktalı ve noktasız i ayrımı yoktur: küçük i'nin büyüğü I'dır. Türkçede ise iki ayrı çift var: ı ile I, i ile İ. Sonuç:

ders9.js
console.log("iyi oyunlar".toUpperCase())console.log("İYİ OYUNLAR".toLowerCase())console.log("İYİ OYUNLAR".toLowerCase().includes("iyi"))console.log("İ".toLowerCase().length)
Çıktı
IYI OYUNLARi̇yi̇ oyunlarfalse2

İlk satırda noktalar kayboldu. İkinci satır daha sinsi: İ küçültülünce ekranda i'ye benzeyen ama iki karakterden oluşan bir şey çıktı: bir i ve onun üstüne binen ayrı bir nokta işareti. Fark etmeyebilirsin, ama dördüncü satır uzunluğun 2 olduğunu söylüyor. Üçüncü satırın false vermesinin sebebi bu: sohbet filtren "İYİ" yazan herkesi kaçırır.

Çözüm, dili söyleyerek çevirmek:

ders9.js
console.log("iyi oyunlar".toLocaleUpperCase("tr"))console.log("İYİ OYUNLAR".toLocaleLowerCase("tr"))console.log("İYİ OYUNLAR".toLocaleLowerCase("tr").includes("iyi"))
Çıktı
İYİ OYUNLARiyi oyunlartrue

toLocaleUpperCase ve toLocaleLowerCase parantezde verdiğin dilin kurallarını kullanır; "tr" Türkçe demek.

Türkçe kurallar da her yerde doğru değildir. "tr" her I'yı ı yapar; İngilizce bir sözcüğü Türkçe kuralla küçültürsen bu kez o bozulur:

ders9.js
console.log("DOUBLE KILL".toLocaleLowerCase("tr"))console.log("DOUBLE KILL".toLowerCase())
Çıktı
double kılldouble kill

Kural: metin hangi dildeyse onun kuralını kullan. Türkçe metinde toLocaleUpperCase("tr") ve toLocaleLowerCase("tr"); İngilizce sözcüklerde, komutlarda ve oyuncu etiketi gibi kodlarda düz toUpperCase ve toLowerCase.

Metinden sayıya, sayıdan metne

Ders 1'de "5" + 3 işleminin 53 verdiğini görmüştün: +'nın bir yanında metin varsa toplamaz, yapıştırır. Sorun şu ki dışarıdan gelen sayılar çoğu zaman metin olarak gelir: klavyeden yazılan, dosyadan okunan, bir siteden gelen ya da split ile ayrılan her şey. Hesaba başlamadan önce onları sayıya çevirmen gerekir.

ders9.js
const altinMetni = "300"console.log(altinMetni + 50)console.log(Number(altinMetni) + 50)
Çıktı
30050350

Number, parseInt, parseFloat

Metni sayıya çevirmenin üç yolu var. Farkları, metin tam bir sayı olmadığında ortaya çıkar:

ders9.js
console.log(Number("12 kill"), parseInt("12 kill"))console.log(Number("3.5"), parseInt("3.5"), parseFloat("3.5"))console.log(Number("3,5"), parseFloat("3,5"))console.log(Number(""), parseInt(""))
Çıktı
NaN 123.5 3 3.5NaN 30 NaN
MetinNumberparseIntparseFloat
"42"424242
"3.5"3.533.5
"12 kill"NaN1212
"kill 12"NaNNaNNaN
"3,5"NaN33
" 7 "777
"" (boş)0NaNNaN
  • Number metnin tamamının sayı olmasını ister; değilse NaN verir (birazdan ayrıntısıyla). Baştaki ve sondaki boşlukları affeder. Boş metni ise 0 sayar: kullanıcı hiçbir şey yazmasa da elinde bir 0 olur, dikkat.
  • parseInt baştan okumaya başlar, sayı olmayan ilk karakterde durur ve o ana kadar okuduğu tam sayıyı verir. Küsuratı yuvarlamaz, keser: parseInt("3.9") sonucu 3.
  • parseFloat da baştan okur ama ondalıklı sayıyı da alır.

Hangisini seçmeli? Kural olarak Number: metin tam bir sayı değilse bunu sana açıkça söyler. parseInt ve parseFloat'ı yalnızca "12 kill", "3.5 saniye" gibi sayının arkasından yazı geldiğini bildiğin durumlarda kullan.

Sayıdan metne: String, şablon metin ve toFixed

Ters yönde de birkaç yol var. String(sayi) sayıyı metne çevirir; şablon metne koymak da aynı işi görür:

ders9.js
const kill = 7console.log(String(kill) + 1)console.log(`${kill}` + 1)console.log(kill + 1)
Çıktı
71718

Ondalıklı bir sayıyı belli sayıda basamakla göstermek için toFixed(basamak) var. Fazla basamakları yuvarlayarak atar, eksik basamakları sıfırla doldurur:

ders9.js
const kda = 16 / 3console.log(kda)console.log(kda.toFixed(2))console.log(kda.toFixed(0))console.log((5).toFixed(2))
Çıktı
5.3333333333333335.3355.00

Son satırdaki parantez şart. 5.toFixed(2) yazarsan JavaScript 5.'i ondalıklı bir sayının başı sanır ve SyntaxError: Invalid or unexpected token verir. Değişkenle (kda.toFixed(2)) böyle bir sorun yok.

Number(metin) parseInt(metin) parseFloat(metin) Metin "42" Sayı 42 String(sayi) `${sayi}` sayi.toFixed(2) Number("42abc") NaN
Şekil 9.4 Metin ile sayı arasındaki köprüler. Sayıya çevrilemeyen metin hata vermez, NaN olur.

NaN: sayı olmayan sayı

Number("12 kill") sonucundaki NaN, İngilizce Not a Number (sayı değil) sözünün kısaltması. JavaScript bir sayı üretmesi gerekirken üretemediğinde program durmaz; bu özel değeri verir ve yoluna devam eder.

Ders 3'te "R: " + maliyet - mana satırının NaN verdiğini görmüş, sebebini bu derse bırakmıştık. + bir metinle karşılaşınca yapıştırır. -, * ve / ise yalnızca sayılarla çalışır, bu yüzden JavaScript metni önce sessizce sayıya çevirmeyi dener:

ders9.js
console.log("300" - 50)console.log("300" + 50)console.log("R: 100" - 90)
Çıktı
25030050NaN

"300" sayıya çevrilebildiği için çıkarma çalıştı; "R: 100" çevrilemedi ve NaN oldu. Bu sessiz çevirmeye güvenme: hesaba girecek metni her zaman kendin, Number ile çevir.

NaN'ın asıl tehlikesi bulaşıcı olması. Ahri'nin objesinde olum alanını olumm diye yanlış yazdığını düşün:

ders9.js
const ahri = { kill: 7, olum: 2, asist: 9 }const kda = (ahri.kill + ahri.asist) / ahri.olummconsole.log(kda)console.log(kda * 2 + 1)console.log(`KDA: ${kda.toFixed(2)}`)
Çıktı
NaNNaNKDA: NaN

olumm diye bir alan yok, değeri undefined (Ders 4). undefined ile bölme NaN verdi, NaN da girdiği her hesaba bulaştı. Program hiç hata vermedi ve yanlış sonuç sessizce ekrana kadar geldi: bir hata mesajı yeri gösterirdi, NaN'ın izini ise sen sürmelisin. Bu bir mantık hatası: kod çalışıyor, sonuç yanlış.

NaN nasıl yakalanır?

Akla ilk gelen deger === NaN hiçbir zaman çalışmaz: NaN hiçbir şeye eşit değildir, kendisine bile.

ders9.js
const sayi = Number("on iki")console.log(sayi === NaN)console.log(Number.isNaN(sayi))
Çıktı
falsetrue

Doğru araç Number.isNaN(deger): değer NaN ise true döndürür. Dışarıdan gelen bir metni sayıya çevirdikten hemen sonra bununla denetle:

ders9.js
const girilen = "12 kill"const kill = Number(girilen)if (Number.isNaN(kill)) {    console.log(`"${girilen}" bir sayı değil`)} else {    console.log(`Kill: ${kill}`)}
Çıktı
"12 kill" bir sayı değil

girilen'i "12" yapıp yeniden çalıştır: bu kez Kill: 12 yazmalı. İki kolu da denemek, Ders 2'den beri yaptığın sınır değeri denemesinin bir parçası.

Math ile yuvarlamak ve sınırlamak

Ders 1'de 10 / 3 sonucunun 3.3333333333333335 çıktığını görmüş, yuvarlamayı bu derse bırakmıştık. Ders 6'da da Math.floor ile rastgele hasarın küsuratını atmıştın. Math, hesap araçlarının durduğu hazır bir obje; içinde yuvarlamak ve sınırlamak için başka araçlar da var.

round, floor, ceil

ders9.js
console.log(Math.round(2.4), Math.round(2.5), Math.round(2.6))console.log(Math.floor(2.4), Math.floor(2.9))console.log(Math.ceil(2.1), Math.ceil(2.9))
Çıktı
2 3 32 23 3
  • Math.round: en yakın tam sayıya gider; tam ortadaki .5 yukarı yuvarlanır.
  • Math.floor: her zaman aşağı (İngilizcesi floor, taban).
  • Math.ceil: her zaman yukarı (İngilizcesi ceiling, tavan).
2 2.5 3 en yakın 2.3 Math.floor(2.3) → 2 Math.round(2.3) → 2 Math.ceil(2.3) → 3 2 2.5 3 en yakın 2.7 Math.floor(2.7) → 2 Math.round(2.7) → 3 Math.ceil(2.7) → 3
Şekil 9.5 Sayı doğrusunda üç yuvarlama. floor hep aşağıdaki, ceil hep yukarıdaki tam sayıya gider; round hangisi yakınsa ona.

Hangisini ne zaman seçeceğini, soruyu oyuna çevirerek bulursun:

ders9.js
const deneyim = 1000const seviyeBasina = 280console.log(`Tam seviye: ${Math.floor(deneyim / seviyeBasina)}`) const baronCani = 3600const saniyeHasari = 250console.log(`Baron ${Math.ceil(baronCani / saniyeHasari)} saniyede düşer`) const canYuzdesi = 640 / 900 * 100console.log(`Can: %${Math.round(canYuzdesi)}`)
Çıktı
Tam seviye: 3Baron 15 saniyede düşerCan: %71
  • 1000 / 280 yaklaşık 3.57. Yarım seviye sayılmaz; kaç tam seviye atlandığını floor verir.
  • 3600 / 250 sonucu 14.4. 14 saniyede düşmeyen Baron'a 15. saniyede de vurman gerekir: "kaç tane gerekir?" sorusunun cevabı ceil.
  • Ekranda gösterilecek bir yüzde için en yakını, round.

max, min ve abs

ders9.js
console.log(Math.max(3, 8, 5))console.log(Math.min(3, 8, 5))console.log(Math.abs(-1200))
Çıktı
831200

Math.max verdiğin sayıların en büyüğünü, Math.min en küçüğünü döndürür. Oyunda asıl işleri sınırlamaktır: can 0'ın altına inmemeli, iksir canı en yüksek değerin üstüne çıkarmamalı.

ders9.js
const maxHp = 800let hp = 120hp = Math.max(0, hp - 300)console.log(`Darbeden sonra: ${hp}`)hp = Math.min(maxHp, hp + 1000)console.log(`İksirden sonra: ${hp}`)
Çıktı
Darbeden sonra: 0İksirden sonra: 800

Math.max(0, hp - 300) şunu der: "hp - 300 ile 0'dan hangisi büyükse onu al." Sonuç eksiye düşerse 0 kazanır. Ders 2'de bunu bir if ile yapardın; Math.max aynı işi tek satırda görür. Math.min(maxHp, …) de tavanı koyar.

Math.abs bir sayının eksi işaretini atar, yalnızca büyüklüğünü bırakır. İki takım arasındaki altın farkını, kimin önde olduğuna bakmadan hesaplamak için:

ders9.js
const maviAltin = 38750const kirmiziAltin = 41200console.log(maviAltin - kirmiziAltin)console.log(`Altın farkı: ${Math.abs(maviAltin - kirmiziAltin)}`)
Çıktı
-2450Altın farkı: 2450

Belli bir basamağa yuvarlamak

Math.round hep tam sayıya yuvarlar. Bir basamak istiyorsan sayıyı 10 ile çarp, yuvarla, 10'a böl; iki basamak için 100 ile:

ders9.js
const kda = 16 / 3console.log(Math.round(kda * 10) / 10)console.log(Math.round(kda * 100) / 100)console.log(kda.toFixed(2))
Çıktı
5.35.335.33

Son iki satır aynı görünüyor ama biri sayı, öteki metin:

Ne yapacaksın?Kullan
Hesaba devam edeceksinMath.round(x * 100) / 100 sayı verir: 5.33
Yalnızca ekrana yazacaksınx.toFixed(2) metin verir: "5.33", hep iki basamaklı ("5.00")

Ondalık tuzağı: 0.1 + 0.2

Şunu çalıştırmadan önce sonucu tahmin et:

ders9.js
console.log(0.1 + 0.2)console.log(0.1 + 0.2 === 0.3)
Çıktı
0.30000000000000004false

JavaScript bozuk değil. Bilgisayar sayıları ikilik sistemde, yalnızca 0 ve 1 ile saklar. Onluk sistemde üçte biri sonlu sayıda basamakla yazamadığın gibi (0.3333…), ikilik sistemde de 0.1 sonlu basamakla yazılamaz.

Bilgisayar bir yerde keser ve küçük bir yuvarlama payı kalır; Ders 1'deki 3.3333333333333335'in sonundaki 5 de bu kesmenin iziydi. Bu JavaScript'e özgü değil: Python, Java, C# gibi dillerde de 0.1 + 0.2, 0.3'e eşit çıkmaz.

Bu küçük pay, ekranda çirkin durmasından çok karşılaştırmaları bozduğu için önemlidir. Çözümler:

ders9.js
const toplam = 0.1 + 0.2console.log(toplam.toFixed(2))console.log(Math.round(toplam * 100) / 100)console.log(Math.round(toplam * 100) / 100 === 0.3)
Çıktı
0.300.3true
  1. Ekranda gösterirken toFixed ile basamak sayısını sınırla.
  2. Ondalıklı iki sayıyı karşılaştırmadan önce ikisini de aynı basamağa yuvarla.
  3. Kuruşu kuruşuna doğru olması gereken değerleri, örneğin parayı, tam sayı olarak tut: 19,99 lirayı 19.99 değil 1999 kuruş olarak saklamak bu sorunu baştan ortadan kaldırır. Oyundaki altın zaten tam sayıdır; tuzak yalnızca ondalıklı değerlerde çıkar.

Uygulama: KDA ve kazanma oranı

Şimdi hepsini birleştir. LoL'ün maç geçmişinde skor 7/2/9 biçiminde yazılır: kill, ölüm, asist. KDA, kill ve asist toplamının ölüm sayısına bölümüdür; ne kadar yüksekse oyuncu o kadar az ölüp o kadar çok katkı vermiştir. Programı adım adım kuracağız: hedef, birkaç maçlık geçmişi metin olarak alıp her maçın KDA'sını, genel KDA'yı ve kazanma oranını hizalı bir tabloda göstermek.

Adım 1: skoru parçala

ders9.js
const skor = "7/2/9"const parcalar = skor.split("/")console.log(parcalar)console.log(parcalar[0] + parcalar[2])
Çıktı
[ '7', '2', '9' ]79

Kill ile asisti toplamak isterken 79 çıktı: dizideki tek tırnaklar parçaların metin olduğunu söylüyor, + de onları yapıştırdı. Her parçayı sayıya çevir:

ders9.js
const parcalar = "7/2/9".split("/")const kill = Number(parcalar[0])const olum = Number(parcalar[1])const asist = Number(parcalar[2])const kda = (kill + asist) / olumconsole.log(`KDA: ${kda.toFixed(2)}`)
Çıktı
KDA: 8.00

Adım 2: hiç ölmeyen oyuncu

Aynı kodu 10/0/6 skoruyla çalıştır:

ders9.js
const parcalar = "10/0/6".split("/")const kill = Number(parcalar[0])const olum = Number(parcalar[1])const asist = Number(parcalar[2])const kda = (kill + asist) / olumconsole.log(`KDA: ${kda.toFixed(2)}`)
Çıktı
KDA: Infinity

Sıfıra bölmek hata vermez, Infinity (sonsuz) verir; bunu Ders 1'de görmüştün. toFixed de onu olduğu gibi metne çevirdi. Maç istatistiği gösteren siteler bu durumda genellikle "Perfect" (kusursuz) yazar; sen de bölmeden önce ölüm sayısına bakmalısın. İşi bir fonksiyona koy:

ders9.js
function kdaMetni(kill, olum, asist) {    if (olum === 0) {        return "Kusursuz"    }    return ((kill + asist) / olum).toFixed(2)} console.log(kdaMetni(7, 2, 9))console.log(kdaMetni(10, 0, 6))console.log(kdaMetni(1, 8, 2))console.log(kdaMetni(0, 0, 0))
Çıktı
8.00Kusursuz0.38Kusursuz

olum 0 ise fonksiyon erken çıkış yapar ve bölme satırına hiç gelinmez. Son satıra dikkat: hiç oynamamış gibi duran 0/0/0 da "Kusursuz" sayıldı. Hata değil ama tartışmalı bir sonuç; "çalışıyor" ile "doğru" arasındaki farkı yine sınır değeri gösterdi. İstersen kill + asist 0 iken ayrı bir metin döndürebilirsin.

Adım 3: kazanma oranı

ders9.js
function oranMetni(galibiyet, macSayisi) {    const yuzde = galibiyet / macSayisi * 100    return `%${yuzde.toFixed(1)}`} console.log(oranMetni(3, 5))console.log(oranMetni(2, 3))console.log(oranMetni(0, 0))
Çıktı
%60.0%66.7%NaN

0 / 0 sonucu Infinity değil NaN'dır: sıfırın sıfıra bölümü tanımsızdır. Hiç maç oynamamış birine %NaN göstermek istemezsin; yine bölmeden önce denetle. Bir de Türkçede ondalık ayırıcı virgüldür ve yüzde işareti sayının önüne gelir. toFixed'in verdiği metindeki noktayı replace ile virgüle çevir:

ders9.js
function oranMetni(galibiyet, macSayisi) {    if (macSayisi === 0) {        return "maç yok"    }    const yuzde = galibiyet / macSayisi * 100    return `%${yuzde.toFixed(1).replace(".", ",")}`} console.log(oranMetni(3, 5))console.log(oranMetni(2, 3))console.log(oranMetni(0, 0))
Çıktı
%60,0%66,7maç yok

Sıra önemli: önce hesap (sayı), sonra toFixed (metin), en son replace (metin). Virgüllü metin artık hesaba girmemeli; Number onu anlamaz.

Hepsi bir arada

Maç geçmişi tek bir metin olarak geliyor: maçlar ", " ile ayrılmış, her maçta skor ve sonuç var (G galibiyet, M mağlubiyet). ders9.js'in içini boşaltıp programın tamamını yaz:

ders9.js
function kdaMetni(kill, olum, asist) {    if (olum === 0) {        return "Kusursuz"    }    return ((kill + asist) / olum).toFixed(2)} function oranMetni(galibiyet, macSayisi) {    if (macSayisi === 0) {        return "maç yok"    }    const yuzde = galibiyet / macSayisi * 100    return `%${yuzde.toFixed(1).replace(".", ",")}`} const gecmis = "7/2/9 G, 3/5/4 M, 10/0/6 G, 1/8/2 M, 5/3/11 G"const maclar = gecmis.split(", ")let toplamKill = 0let toplamOlum = 0let toplamAsist = 0let galibiyet = 0 console.log("Maç  Skor     KDA       Sonuç")for (let i = 0; i < maclar.length; i++) {    const parcalar = maclar[i].split(" ")    const skor = parcalar[0]    const sonuc = parcalar[1]    const sayilar = skor.split("/")    const kill = Number(sayilar[0])    const olum = Number(sayilar[1])    const asist = Number(sayilar[2])     toplamKill = toplamKill + kill    toplamOlum = toplamOlum + olum    toplamAsist = toplamAsist + asist    if (sonuc === "G") {        galibiyet++    }     const sira = String(i + 1).padEnd(5)    const kda = kdaMetni(kill, olum, asist).padEnd(10)    console.log(`${sira}${skor.padEnd(9)}${kda}${sonuc}`)} const genelKda = kdaMetni(toplamKill, toplamOlum, toplamAsist)const oran = oranMetni(galibiyet, maclar.length)console.log(`Genel KDA: ${genelKda}`)console.log(`Kazanma oranı: ${oran} (${galibiyet}/${maclar.length})`)
Çıktı
Maç  Skor     KDA       Sonuç1    7/2/9    8.00      G2    3/5/4    1.40      M3    10/0/6   Kusursuz  G4    1/8/2    0.38      M5    5/3/11   5.33      GGenel KDA: 3.22Kazanma oranı: %60,0 (3/5)

Programı yukarıdan aşağı oku:

  1. split(", ") geçmişi maçlara ("7/2/9 G"…), split(" ") her maçı skor ve sonuca, split("/") da skoru üç parçaya böler. Her parça Number ile sayıya çevrilir.
  2. Toplamlar döngüden önce açılan kutularda birikir (Ders 5'teki saymak ve toplamak kalıbı).
  3. Her satır padEnd ile aynı genişliğe tamamlanmış hücrelerden kurulur. Sıra numarası sayı olduğu için önce String ile metne çevrildi; kdaMetni ise zaten metin döndürüyor.
  4. Genel KDA, maçların KDA'larının ortalaması değil: bütün kill ve asistlerin toplamı, bütün ölümlerin toplamına bölünür. Böylece ölümsüz geçen "Kusursuz" maçlar da hesaba katılır.

Sınırları sen dene: geçmişe 0/0/0 M gibi bir maç ekle, sonra gecmis'i boş metin ("") yap. Boş geçmişte tabloda NaN ve undefined göreceksin: "".split(", ") boş bir dizi değil, içinde tek bir boş metin olan bir dizi verir. Bozuk girdiyle başa çıkmayı Ders 13'te öğreneceksin; şimdilik bu sonuçların nereden geldiğini açıklayabilmen yeter.

Sık hatalar

Bu dersin hataları. Bütün derslerin hatalarını hata rehberinde de bulabilirsin.

Sık hataTypeError: kill.padStart is not a function

Ne zaman çıkar? Bir metin metodunu sayıda çağırınca. Sayıların padStart, toUpperCase, includes, slice gibi metotları yoktur.

ders9.js
const kill = 7console.log(kill.padStart(3))
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(kill.padStart(3))                 ^ TypeError: kill.padStart is not a function    at Object.<anonymous> (C:\kod\ogren\ders9.js:2:18)    ... Node.js v24.20.0

Nasıl düzelir? "is not a function": sayıların padStart diye bir metodu yok. Önce metne çevir: String(kill).padStart(3).

Sık hataTypeError: oran.toFixed is not a function

Ne zaman çıkar? Tersi: sayı metodu olan toFixed'i metinde çağırınca. Değer çoğu zaman split'ten ya da dışarıdan metin olarak gelmiştir.

ders9.js
const oran = "56.25"console.log(oran.toFixed(1))
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(oran.toFixed(1))                 ^ TypeError: oran.toFixed is not a function    at Object.<anonymous> (C:\kod\ogren\ders9.js:2:18)    ... Node.js v24.20.0

Nasıl düzelir? Önce sayıya çevir: Number(oran).toFixed(1). Bu hatanın bir başka sebebi toFixed'i iki kez çağırmaktır; ilk toFixed zaten metin döndürür.

Sık hataTypeError: isim.toUppercase is not a function

Ne zaman çıkar? Metot adını yanlış yazınca. Metot adları camelCase'tir ve büyük-küçük harfe duyarlıdır: toUpperCase doğru; toUppercase, touppercase, ToUpperCase yanlış. Aynı hata Number.isNan (doğrusu isNaN) ve Math.Round (doğrusu round) için de çıkar.

ders9.js
const isim = "Teemo"console.log(isim.toUppercase())
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(isim.toUppercase())                 ^ TypeError: isim.toUppercase is not a function    at Object.<anonymous> (C:\kod\ogren\ders9.js:2:18)    ... Node.js v24.20.0

Nasıl düzelir? Adı harfi harfine yaz. Ders 5'teki takim.Push hatasının metindeki karşılığı: nokta koyduğunda VS Code'un önerdiği listeden seçersen yazım hatası yapmazsın. Math'i küçük harfle yazarsan (math.round) mesaj bu kez ReferenceError: math is not defined olur.

Sık hataSyntaxError: Unexpected end of input (kapanmamış ters tırnak)

Ne zaman çıkar? Ters tırnağı açıp kapatmayı unutunca. Çift tırnaklı metin satır sonunda biter; ters tırnaklı metin ise çok satırlı olabildiği için JavaScript kapanışı dosyanın sonuna kadar arar, bulamayınca "girdi beklenmedik yerde bitti" der.

ders9.js
const isim = "Ahri"console.log(`Merhaba ${isim})
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(`Merhaba ${isim})  SyntaxError: Unexpected end of input    at wrapSafe (node:internal/modules/cjs/loader:1861:18)    ... Node.js v24.20.0

Son satırdan sonra Enter'a bastıysan mesaj dosyanın en sondaki boş satırını gösterir: ders9.js:3 ve altında boş bir kod satırı. Dosyada aşağıda başka bir ters tırnak varsa mesaj yine değişir, çünkü JavaScript metni o ters tırnağa kadar uzatır:

ders9.js
const isim = "Ahri"console.log(`Merhaba ${isim})console.log(`Hoş geldin`)
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(`Merhaba ${isim}) SyntaxError: missing ) after argument list    at wrapSafe (node:internal/modules/cjs/loader:1861:18)    ... Node.js v24.20.0

Nasıl düzelir? Mesajlar ters tırnaktan söz etmez, ^ da göstermez; Ders 2'deki eksik süslü parantezde olduğu gibi, gösterilen satır sorunun başladığı yer olmayabilir. Renklere bak: kapanmamış şablondan sonraki kod bir sonraki ters tırnağa kadar metin rengine boyanır (ikinci örnekte 3. satırdaki console.log( gibi). Oradan geriye doğru ilk ters tırnağı bul ve kapat.

Sık hata${kda} olduğu gibi ekrana çıkıyor

Ne zaman çıkar? Yuvayı çift ya da tek tırnaklı metnin içine yazınca. Hata mesajı çıkmaz; program çalışır ama yanlış yazar.

ders9.js
const kda = "8.00"console.log("KDA: ${kda}")
Çıktı
KDA: ${kda}

Nasıl düzelir? Tırnakları ters tırnakla değiştir: `KDA: ${kda}`. Türkçe Q klavyede AltGr + ,, ardından Boşluk.

Sık hataSonuç NaN çıkıyor ama hata mesajı yok

Ne zaman çıkar? Hesaba sayıya çevrilemeyen bir metin ya da undefined girince: yanlış yazılmış bir obje alanı, split'ten beklenenden az parça, virgüllü bir sayı ("3,5").

ders9.js
const parcalar = "7-2-9".split("/")const kill = Number(parcalar[0])const asist = Number(parcalar[2])console.log(kill + asist)
Çıktı
NaN

Nasıl düzelir? Geriye doğru iz sür: hesaba giren her değeri console.log ile yazdır (Ders 7). Burada parcalar dizisi [ '7-2-9' ] çıkar; skorun ayırıcısı / değil -. Dışarıdan gelen her değeri çevirdikten hemen sonra Number.isNaN ile denetlersen sorunu kaynağında yakalarsın.

Sık hataTypeError: Cannot read properties of undefined (reading 'trim')

Ne zaman çıkar? split beklediğinden az parça verince, olmayan parçanın metodunu çağırırsan. Olmayan parça undefined'dır ve undefined'ın ne alanı ne metodu vardır (Ders 5'te enYuksek.isim ile görmüştün).

ders9.js
const parcalar = "Ahri".split(":")console.log(parcalar[1].trim())
Hata çıktısı
C:\kod\ogren\ders9.js:2console.log(parcalar[1].trim())                        ^ TypeError: Cannot read properties of undefined (reading 'trim')    at Object.<anonymous> (C:\kod\ogren\ders9.js:2:25)    ... Node.js v24.20.0

Nasıl düzelir? Metinde : olmadığı için dizinin tek elemanı var, parcalar[1] yok. Parçaları kullanmadan önce sayısını denetle (parcalar.length === 2) ya da bölmeden önce includes(":") ile ayırıcının varlığına bak.

Sık hataMetot çalıştı ama metin değişmedi

Ne zaman çıkar? Metodun sonucunu bir yere koymayınca. Hata mesajı yok, metin eski hâliyle kalır.

ders9.js
let isim = "  teemo "isim.trim()isim.toUpperCase()console.log(`[${isim}]`)
Çıktı
[  teemo ]

Nasıl düzelir? Metin metotları yeni metin döndürür. Sonucu kutuya geri koy: isim = isim.trim().toUpperCase().

Sık hataEkrana [Function: toUpperCase] yazıyor

Ne zaman çıkar? Metodu parantezsiz yazınca. Parantez yoksa metot çalışmaz; JavaScript sana metodun kendisini gösterir. Ders 3'teki parantezsiz fonksiyon çağrısının aynısı.

ders9.js
const isim = "Teemo"console.log(isim.toUpperCase)
Çıktı
[Function: toUpperCase]

Nasıl düzelir? Parantezi ekle: isim.toUpperCase(). length ise tersine parantezsiz yazılır; o bir metot değil, alan.

Sık hataTürkçe metin karşılaştırması tutmuyor (İ ve i)

Ne zaman çıkar? Türkçe metni toLowerCase ya da toUpperCase ile çevirip karşılaştırınca. "İ" küçültülünce iki karakterli bir i̇ olur, "i" büyütülünce noktasız I olur.

ders9.js
console.log("İKSİR".toLowerCase() === "iksir")console.log("İKSİR".toLocaleLowerCase("tr") === "iksir")
Çıktı
falsetrue

Nasıl düzelir? Türkçe metinde toLocaleLowerCase("tr") ve toLocaleUpperCase("tr") kullan; parantezdeki "tr"yi unutma.

Görevler

Görevleri, başka bir dosya söylenmedikçe ders9.js'te yap; önceki kodu sil ya da yorum satırı yap. Önce kendin dene, takılırsan ipuçlarını sırayla aç. Çözüme en son bak.

Görev 1

Şampiyon kartı

Şu değişkenlerle başla:

JavaScript
const isim = "Lux"const unvan = "ışığın leydisi"const mana = 320const maxMana = 500

Tek bir console.log ve tek bir şablon metinle şu iki satırı yazdır:

Metin
IŞIĞIN LEYDİSİLux - Mana 320/500 (%64)

Yüzdeyi elle yazmak yok; en yakın tam sayıya yuvarlanmış olarak JavaScript hesaplasın. Bitince mana'yı 0, 500 ve 333 yapıp dene: %0, %100 ve %67 çıkmalı.

İpucu 1

Unvanda ı ve i var. Hangi metot Türkçe harfleri doğru büyütüyordu?

İpucu 2

Yüzde mana / maxMana * 100; en yakına yuvarlamak için Math.round. Hepsini ${ } yuvasının içine yazabilirsin.

İpucu 3

İki satır için şablon metnin içinde gerçekten alt satıra geç. İkinci satırı en baştan yaz; girintisiz.

Çözümü göster
ders9.js
const isim = "Lux"const unvan = "ışığın leydisi"const mana = 320const maxMana = 500console.log(`${unvan.toLocaleUpperCase("tr")}${isim} - Mana ${mana}/${maxMana} (%${Math.round(mana / maxMana * 100)})`)
Çıktı
IŞIĞIN LEYDİSİLux - Mana 320/500 (%64)

toUpperCase kullansaydın ilk satır IŞIĞIN LEYDISI çıkardı. 333 için gerçek yüzde 66.6'dır; Math.round onu 67 yapar.

Görev 2

Saldırı hızı

Bir şampiyonun saldırı hızı, istatistik ekranından metin olarak okunuyor: const ekran = "0.7 saldırı/sn". Hızı bu metinden sayı olarak al. Aldığı her eşya hızı 0.1 artırıyor; bir for döngüsüyle üç eşya ekle. Sonra hızı iki basamakla yazdır ve hız en az 1 ise Hızlı saldırı açıldı, değilse Henüz yavaş yazdır:

Metin
Saldırı hızı: 1.00Hızlı saldırı açıldı

Önce yuvarlama yapmadan dene ve ne olduğuna bak. Sonra düzelt.

İpucu 1

Number(ekran) burada NaN verir. Ondalıklı sayıyı okuyup arkasındaki yazıyı umursamayan çevirici hangisiydi?

İpucu 2

Yuvarlamadan çalıştırınca ekranda 1.00 yazıp ardından Henüz yavaş geliyorsa sebebi bu dersin "Ondalık tuzağı" bölümünde.

İpucu 3

Karşılaştırmadan önce yuvarla: hiz = Math.round(hiz * 100) / 100. Ekrana yazarken hiz.toFixed(2).

Çözümü göster
ders9.js
const ekran = "0.7 saldırı/sn"let hiz = parseFloat(ekran)for (let i = 0; i < 3; i++) {    hiz = hiz + 0.1}hiz = Math.round(hiz * 100) / 100console.log(`Saldırı hızı: ${hiz.toFixed(2)}`)if (hiz >= 1) {    console.log("Hızlı saldırı açıldı")} else {    console.log("Henüz yavaş")}
Çıktı
Saldırı hızı: 1.00Hızlı saldırı açıldı

parseInt kullansaydın küsurat atılır, hız 0'dan başlardı. Yuvarlama satırını silersen hiz 0.9999999999999999 olur: ekranda toFixed(2) sayesinde 1.00 görünür ama hiz >= 1 false verir ve Henüz yavaş yazılır. Ekranda doğru görünen bir değer karşılaştırmada yanlış çıkabilir. Sınır denemesi: döngüyü 2 tura indir; 0.90 ve Henüz yavaş çıkmalı.

Görev 3

Skor tablonu hizala

Ders 8'de yazdığın skor.js'i aç. Tablosu şöyle çıkıyordu; ad uzadıkça arkasındaki her şey kayıyor:

Metin
Garen 4/6/5: 5 puan (Orta)Lux 2/3/14: 14 puan (Orta)Jinx 11/2/6: 35 puan (Yıldız)Teemo 0/9/3: -15 puan (Zor maç)Ahri 7/4/7: 20 puan (İyi)

skorTablosu fonksiyonunu bu dersteki araçlarla düzenle: + ile kurulan satırları şablon metne çevir, başlığın altına bir sütun başlıkları satırı ekle ve sütunları hizala. İsim ve skor 8'er karakterlik sütunlara sola, puan 5 karakterlik sütuna sağa yaslansın; unvan iki boşluk sonra gelsin:

Metin
--- Skor tablosu ---İsim    Skor     Puan  UnvanGaren   4/6/5       5  OrtaLux     2/3/14     14  OrtaJinx    11/2/6     35  YıldızTeemo   0/9/3     -15  Zor maçAhri    7/4/7      20  İyiTakım puanı: 59MVP: Jinx (35 puan)Maç verisi yok

skor.js elinde yoksa Ders 8'deki "Skor tablosu" görevinin çözümünü yaz, sonra düzenle. Dosyanın sonunda Ders 8'in sınır denemesi satırları duruyorsa şimdilik başlarına // koy; beklenen çıktı yalnızca iki skorTablosu çağrısınınki.

İpucu 1

Puan bir sayı, padStart ise metin metodu: önce String(p).

İpucu 2

Sütun başlıkları satırı da aynı genişliklerle kurulur: "İsim".padEnd(8), "Skor".padEnd(8), "Puan".padStart(5).

İpucu 3

Oyuncu satırı dört parçadan oluşur: o.isim.padEnd(8), kda.padEnd(8), String(p).padStart(5) ve iki boşluktan sonra unvan(p). Hepsini tek bir şablon metnin yuvalarına koy. kda kutusunu da şablon metinle kur: `${o.kill}/${o.olum}/${o.asist}`.

Çözümü göster
skor.js
const oyuncular = [    { isim: "Garen", kill: 4, olum: 6, asist: 5 },    { isim: "Lux", kill: 2, olum: 3, asist: 14 },    { isim: "Jinx", kill: 11, olum: 2, asist: 6 },    { isim: "Teemo", kill: 0, olum: 9, asist: 3 },    { isim: "Ahri", kill: 7, olum: 4, asist: 7 }] function puan(oyuncu) {    return oyuncu.kill * 3 + oyuncu.asist - oyuncu.olum * 2} function unvan(p) {    if (p >= 30) {        return "Yıldız"    } else if (p >= 15) {        return "İyi"    } else if (p >= 0) {        return "Orta"    } else {        return "Zor maç"    }} function skorTablosu(liste) {    if (liste.length === 0) {        console.log("Maç verisi yok")        return    }    console.log("--- Skor tablosu ---")    console.log(`${"İsim".padEnd(8)}${"Skor".padEnd(8)}${"Puan".padStart(5)}  Unvan`)    let toplam = 0    let mvp = liste[0]    for (const o of liste) {        const p = puan(o)        const kda = `${o.kill}/${o.olum}/${o.asist}`        console.log(`${o.isim.padEnd(8)}${kda.padEnd(8)}${String(p).padStart(5)}  ${unvan(p)}`)        toplam = toplam + p        if (p > puan(mvp)) {            mvp = o        }    }    console.log(`Takım puanı: ${toplam}`)    console.log(`MVP: ${mvp.isim} (${puan(mvp)} puan)`)} skorTablosu(oyuncular)skorTablosu([])
Çıktı
--- Skor tablosu ---İsim    Skor     Puan  UnvanGaren   4/6/5       5  OrtaLux     2/3/14     14  OrtaJinx    11/2/6     35  YıldızTeemo   0/9/3     -15  Zor maçAhri    7/4/7      20  İyiTakım puanı: 59MVP: Jinx (35 puan)Maç verisi yok

Vurgulu satırlar değişenler. Eksi puan (-15) da sağa yaslandı, çünkü padStart eksi işaretini de bir karakter sayar. Sınır denemesi: listeye 8 karakterden uzun adlı bir oyuncu ekle ("KassadinUstasi"); o satır kayar, çünkü padEnd uzun metni kısaltmaz. Uzun adları slice ile kısaltmayı bir sonraki görevde yapacaksın.

Görev 4

Riot ID

Riot ID'ler Ad#ETİKET biçimindedir. Bir riotId metni için şu kuralları uygulayan bir program yaz:

  1. Baştaki ve sondaki boşlukları at.
  2. Metinde # yoksa Geçersiz Riot ID yaz ve dur.
  3. Ad 8 karakterden uzunsa ilk 8 karakterini al, sonuna ... ekle.
  4. Etiketi büyük harfe çevir. Etiket TR ile başlıyorsa satırın sonuna bir boşluk ve (Türkiye) ekle.
riotIdBeklenen çıktı
" Faker#kr1 "Faker #KR1
"KassadinUstasi#tr1"Kassadin... #TR1 (Türkiye)
"Annie123#tr1"Annie123 #TR1 (Türkiye)
"Teemo"Geçersiz Riot ID
İpucu 1

Sıra: önce trim, sonra includes("#") ile denetim, en son split("#"). split'in verdiği dizinin 0. elemanı ad, 1. elemanı etiket.

İpucu 2

Adı kısaltabilmek için onu let ile tut: if (ad.length > 8) { ad = ad.slice(0, 8) + "..." }. Annie123 tam 8 karakter; kısaltılmamalı.

İpucu 3

Etiketler İngilizce harflerden oluşur, bu yüzden düz toUpperCase doğru seçim. Sonuç satırını let ile kur, gerekirse etiket.startsWith("TR") ile sonuna ekle.

Çözümü göster
ders9.js
const riotId = " Faker#kr1 "const temiz = riotId.trim()if (!temiz.includes("#")) {    console.log("Geçersiz Riot ID")} else {    const parcalar = temiz.split("#")    let ad = parcalar[0]    const etiket = parcalar[1].toUpperCase()    if (ad.length > 8) {        ad = ad.slice(0, 8) + "..."    }    let satir = `${ad} #${etiket}`    if (etiket.startsWith("TR")) {        satir = satir + " (Türkiye)"    }    console.log(satir)}
Çıktı
Faker #KR1

Tablodaki bütün satırları tek tek dene. Bir sınır daha: "#tr1" girersen ad boş kalır ve program başında boşluk olan bir #TR1 (Türkiye) satırı yazar. Çalışıyor ama doğru değil; ad.length === 0 durumunu da geçersiz saymak için koşulu || ile genişletebilirsin.

Görev 5

TFT faizi

TFT'de her turun başında elindeki her 10 altın için 1 altın faiz alırsın, ama en fazla 5. Altın miktarı ekrandan metin olarak okunuyor: const ekran = "47 altın". Faizi ve tam faize, yani 50 altına kaç tur kaldığını hesapla: her tur 5 altın kazandığını, hiç harcamadığını düşün ve faizi tur hesabına katma. Metnin başında sayı yoksa Altın okunamadı yaz.

ekranBeklenen çıktı
"47 altın"Altın: 47, faiz: 4, tam faize 1 tur
"9 altın"Altın: 9, faiz: 0, tam faize 9 tur
"10 altın"Altın: 10, faiz: 1, tam faize 8 tur
"50 altın"Altın: 50, faiz: 5, tam faize 0 tur
"120 altın"Altın: 120, faiz: 5, tam faize 0 tur
"altın yok"Altın okunamadı
İpucu 1

Altın tam sayıdır ve arkasından yazı geliyor. Hangi çevirici tam sayıyı okuyup gerisini umursamıyordu? Okuduktan hemen sonra Number.isNaN ile denetle.

İpucu 2

Faiz için önce kaç tam 10 olduğunu bul (Math.floor). "En fazla 5" bir tavandır: Math.min(5, …).

İpucu 3

Tur sayısı bir "kaç tane gerekir?" sorusu: eksik altını 5'e böl ve Math.ceil ile yukarı yuvarla. 50'yi geçince eksik altın eksiye düşmesin: Math.max(0, 50 - altin).

Çözümü göster
ders9.js
const ekran = "47 altın"const altin = parseInt(ekran)if (Number.isNaN(altin)) {    console.log("Altın okunamadı")} else {    const faiz = Math.min(5, Math.floor(altin / 10))    const eksik = Math.max(0, 50 - altin)    const tur = Math.ceil(eksik / 5)    console.log(`Altın: ${altin}, faiz: ${faiz}, tam faize ${tur} tur`)}
Çıktı
Altın: 47, faiz: 4, tam faize 1 tur

Number("47 altın") NaN verirdi; burada parseInt doğru seçim. Tur hesabında floor kullansaydın 47 altında 0 tur çıkardı, oysa 3 altın eksik; Math.max olmasaydı 120 altında -14 tur görürdün. Sınırlar: 9–10 (faiz), 44–45 (tur), 50–120 (tavan). "0 altın" için faiz: 0 ve 10 tur çıkmalı.

Görev 6

Hasar raporu

Son maçlarındaki hasar değerleri noktalı virgülle ayrılmış tek bir metin olarak geldi. Bazı kayıtlar boş, biri bozuk, bazılarında fazladan boşluk var:

JavaScript
const kayit = "18250; 9400;;23110 ;abc"

Geçerli her maçı hasarı sağa yaslanmış olarak listele, geçersiz kayıtları say, ortalamayı tek basamakla ve Türkçe virgülle, en yüksek hasarı da en sonda yazdır:

Metin
Maç 1:  18250Maç 2:   9400Maç 3:  23110Geçersiz kayıt: 2Ortalama: 16920,0En yüksek: 23110

Hiç geçerli maç yoksa (örneğin ";;abc") ortalama ve en yüksek yerine Geçerli maç yok yazmalı.

İpucu 1

split(";") ile böl, her parçayı trim et ve Number ile çevir. Dikkat: boş parça "" olur ve Number("") 0 verir; boşları ayrıca yakalaman gerek.

İpucu 2

Döngüden önce dört kutu aç: geçerli sayısı, geçersiz sayısı, toplam, en yüksek. En yükseği enYuksek = Math.max(enYuksek, hasar) ile güncelleyebilirsin. Hasarı sağa yaslamak için String(hasar).padStart(6).

İpucu 3

Ortalama: (toplam / gecerli).toFixed(1).replace(".", ","). gecerli 0 iken bu satıra hiç gelme; yoksa 0 / 0 sonucu NaN olur.

Çözümü göster
ders9.js
const kayit = "18250; 9400;;23110 ;abc"const parcalar = kayit.split(";")let gecerli = 0let gecersiz = 0let toplam = 0let enYuksek = 0 for (const parca of parcalar) {    const temiz = parca.trim()    const hasar = Number(temiz)    if (temiz === "" || Number.isNaN(hasar)) {        gecersiz++    } else {        gecerli++        toplam = toplam + hasar        enYuksek = Math.max(enYuksek, hasar)        console.log(`Maç ${gecerli}: ${String(hasar).padStart(6)}`)    }} console.log(`Geçersiz kayıt: ${gecersiz}`)if (gecerli === 0) {    console.log("Geçerli maç yok")} else {    const ortalama = (toplam / gecerli).toFixed(1).replace(".", ",")    console.log(`Ortalama: ${ortalama}`)    console.log(`En yüksek: ${enYuksek}`)}
Çıktı
Maç 1:  18250Maç 2:   9400Maç 3:  23110Geçersiz kayıt: 2Ortalama: 16920,0En yüksek: 23110

kayit'i ";;abc" yap: Geçersiz kayıt: 3 ve Geçerli maç yok çıkmalı. "0" tek başına geçerli bir maçtır (Ortalama: 0,0); temiz === "" denetimi olmasaydı boş kayıtlar da sıfır hasarlı maç sayılırdı. "-5" gibi eksi bir hasarı da şu an kabul ediyor; istersen onu da geçersiz say.

Kendini sına

Soru 1

Bu program ne yazar?

JavaScript
const isim = "Jinx"console.log("Merhaba ${isim}")console.log(`Merhaba ${isim}`)
Cevabı göster

İlk satır Merhaba ${isim} yazar: çift tırnağın içinde yuva çalışmaz, yazı harfi harfine basılır. İkinci satır Merhaba Jinx yazar.

Soru 2

"Sihirdar".slice(2, 5) ne döndürür?

Cevabı göster

"hir". Kesim çizgilerini düşün: 2 numaralı çizgiden başla, 5 numaralı çizgide dur. Arada 2, 3 ve 4 numaralı karakterler var: h, i, r. Bitiş (5) dahil değil.

Soru 3

Bu üç satır ne yazar?

JavaScript
console.log(Number("15 asist"))console.log(parseInt("15 asist"))console.log(Number(""))
Cevabı göster

NaN, 15 ve 0. Number metnin tamamının sayı olmasını ister. parseInt baştan okur ve sayı olmayan ilk karakterde durur. Boş metni ise Number 0 sayar; boş girdiyi ayrıca denetlemen gerekmesinin sebebi bu.

Soru 4

Hangi satır hata verir? Mesajı ne olur?

JavaScript
const kill = 12const metin = "12"console.log(metin.padStart(4))console.log(kill.padStart(4))
Cevabı göster

Hata son satırda çıkar: TypeError: kill.padStart is not a function. padStart bir metin metodu; kill ise bir sayı. Bir önceki satır sorunsuz çalışır: "12"'nin başına iki boşluk ekleyip onu dört karaktere tamamlar. Düzeltmek için String(kill).padStart(4).

Soru 5

Math.round(4.5), Math.floor(4.5), Math.ceil(4.1) ve Math.abs(-4) kaçtır?

Cevabı göster

5, 4, 5 ve 4. round en yakına gider ve tam ortadaki .5'i yukarı yuvarlar. floor her zaman aşağı, ceil her zaman yukarı yuvarlar. abs eksi işaretini atar.

Soru 6

Bu kod neden hiçbir zaman "Geçersiz" yazmaz? Nasıl düzeltirsin?

JavaScript
const deger = Number("abc")if (deger === NaN) {    console.log("Geçersiz")}
Cevabı göster

NaN hiçbir şeye eşit değildir, kendisine bile; deger === NaN her zaman false'tur. Doğrusu if (Number.isNaN(deger)).

Soru 7

"İKSİR".toLowerCase() ile "İKSİR".toLocaleLowerCase("tr") ekranda neredeyse aynı görünür. Aynı mıdır?

Cevabı göster

Değildir. İlkinde her İ, bir i ve ayrı bir nokta işaretinden oluşan iki karaktere dönüşür: sonuç 7 karakter, ikincisi ise 5 karakterlik düz iksir. Bu yüzden "İKSİR".toLowerCase() === "iksir" false verir; Türkçe metinde "tr" ile çevir.

Soru 8

0.1 + 0.2 === 0.3 neden false? İki sayıyı nasıl karşılaştırırdın?

Cevabı göster

Bilgisayar 0.1 ve 0.2'yi ikilik sistemde tam olarak saklayamaz; toplamları 0.30000000000000004 çıkar. Karşılaştırmadan önce iki tarafı aynı basamağa yuvarla: Math.round((0.1 + 0.2) * 100) / 100 === 0.3 true verir.

Kayıt noktası

Bu derste bir dosya ekledin (ders9.js), bir dosyayı da değiştirdin (Görev 3'teki skor.js). VS Code terminalinde, C:\kod\ogren klasöründeyken önce neyin değiştiğine bak, sonra kaydet ve GitHub'a gönder:

Bir sonraki derste fonksiyonları derinlemesine ele alacaksın: ok fonksiyonları, varsayılan parametreler ve bir fonksiyonu başka bir fonksiyona vermek.

İşaret yalnızca bu tarayıcıda saklanır, kimseye gönderilmez.