İki Tür Tip Dönüşümü
JavaScript tipler konusunda oldukça esnektir. Bir operatör "yanlış" tipte bir değer aldığında dil hata fırlatmaz; değeri dönüştürür. İşte bu dönüşüme tip dönüşümü (coercion) deniyor ve iki şekilde karşımıza çıkıyor:
- Açık (explicit) tip dönüşümü — siz talep edersiniz:
Number("42"),String(99),Boolean(value). - Örtük (implicit) tip dönüşümü — siz bir dönüşüm yazmadan, operatörün kendisi tetikler:
"5" - 2,"" == 0,if (value).
İkisi de sonuçta aynı dönüşüm kurallarını çalıştırır. Tek fark, dönüşüme sizin mi yoksa dilin mi karar verdiği. JavaScript'te kafa karıştıran sonuçların neredeyse tamamı — "5" + 1 === "51", [] == false, null == undefined — gafil avlayan örtük tip dönüşümünden kaynaklanır.
Zihinsel model şu: Number(...) veya String(...) yazdığında ne istediğini biliyorsundur. Yazmadığın zaman ise her operatörün ne yapacağına dair kendi fikri vardır — ve bug'lar işte tam da bu fikirlerin içinde yaşar.
Üç Hedef Tip
JavaScript tip dönüşümü her zaman üç primitif tipten birine doğru yapılır: string, number ya da boolean. (Bir de bigint var ama diğer tiplerden ona otomatik dönüşüm olmaz.) Kuralların geri kalanı, operatörün hangi hedefe nişan aldığına göre şekillenir.
String'e dönüşüm en hoşgörülü olanıdır — her değerin bir string karşılığı vardır. Ama dikkat: objeler "[object Object]" gibi hiç işe yaramayan bir şeye dönüşür. Bir objeyi string ile birleştirip loglarken ("user: " + user) istediğinizi neredeyse hiç göremezsiniz bu yüzden. Onun yerine JSON.stringify kullanın veya template literal içinde istediğiniz alanları tek tek yazın.
Number'a dönüşüm (javascript string to number)
Number'a dönüşüm çok daha katıdır. String'in gerçekten sayıya benzemesi gerekir, aksi halde karşınıza NaN çıkar:
Parantez içindeki sürprizler, ezberlemeye değer olanlar:
- Boş string ve yalnızca boşluk içeren stringler
NaNdeğil,0döner. nulldeğeri0olurken,undefinedNaNdöner.- Boş dizi
0olur; tek elemanlı bir dizi o elemanı dönüştürür; birden fazla elemanı olan dizi iseNaNdöner.
İçinde fazladan karakter bulunan bir stringten sayı ayıklamak istiyorsan, Number yerine parseInt veya parseFloat kullan:
parseInt çağırırken radix parametresini (10) her zaman vermeyi alışkanlık haline getirin. Aksi halde "0x" ile başlayan stringler hex olarak yorumlanır ve bu büyük ihtimalle kastettiğiniz şey değildir.
Boolean'a Tip Dönüşümü (Boolean Coercion)
Üç tip dönüşümü içinde en kolayı boolean coercion. Kısa bir liste değer false'a dönüşüyor; geri kalan her şey true.
JavaScript'teki falsy değerler şunlar:
false0,-0,0n""(boş string)nullundefinedNaN
Hepsi bu kadar. Bunların dışındaki her değer — "false", "0", [] ve {} dahil — truthy kabul edilir.
Boş dizi ve boş nesnenin sonucu, özellikle Python'dan gelenleri fena halde yakalar. Python'da boş koleksiyonlar falsy'dir; JavaScript'te ise truthy sayılırlar. "Bu dizi boş mu?" diye sormak istiyorsan, doğrudan arr.length === 0 kontrolü yapmalısın.
Boolean'a dönüşüm (boolean coercion), bir değerin boolean beklenen bir yerde kullanıldığı her durumda devreye girer: if (...), while (...), üçlü operatör ? : ve mantıksal operatörler &&, ||, !.
+ Operatörü Özel Bir Durumdur
Aritmetik operatörlerin çoğu, operandlarını sayıya zorlar. Ama + biraz farklı çalışır — taraflardan herhangi biri string ise + string birleştirme (concatenation) yapar. Aksi halde sayısal toplama işlemini gerçekleştirir.
Değerlendirme soldan sağa yapılır. 1 + 2 + "3" ifadesinde önce 1 + 2 = 3 hesaplanır, ardından 3 + "3" = "33" olur. Ama "1" + 2 + 3 en baştan string moduna girer ve öyle de kalır: önce "12", sonra "123".
İşte bu yüzden string'leri + ile birleştirmek tehlikelidir. Template literal'larda böyle bir dert yok:
Template literal, count + 1 ifadesini önce kendi başına sayısal olarak hesaplar, sonra sonucu yerine yerleştirir. Sürpriz bir tip dönüşümü yok.
Açık (Explicit) Dönüşümleri Tercih Edin
Bir değeri gerçekten dönüştürmeniz gerekiyorsa, bunu açıkça belirtin. Birkaç karakter fazladan yazarsınız ama kodu sonradan okuyacak kişi için hiçbir belirsizlik kalmaz:
Boolean'lar için de aynı şey geçerli. !!value çalışıyor ve sık kullanılıyor ama Boolean(value) ne yaptığını net bir şekilde anlatıyor:
Mantıklı bir kural şu: uygulama mantığında açık dönüşümleri tercih edin; +x, !!x gibi kısa biçimleri ise yalnızca kısalığın önem taşıdığı ve niyetin bağlamdan net anlaşıldığı yerlere saklayın.
== Operatörü Tip Dönüşümüne Fena Halde Yaslanır
Eşitlik operatörleri, JavaScript tip dönüşümünde (type coercion) en çok sürprizle karşılaşacağınız yerdir. == karşılaştırma yapmadan önce dönüşüm uygular; === ise uygulamaz.
Yukarıdaki her bir true, çoğu geliştiricinin ezbere sayamayacağı çok adımlı bir tip dönüşümü zincirinin sonucudur. İşte asıl sorun da bu — kazara çalışan kod, ileride kırılan koddur. Eşitlik kurallarının tamamına bir sonraki sayfada gireceğiz; şimdilik akılda kalması gereken şu: varsayılan olarak === kullanın ve == operatörüne yalnızca x == null deyimi için başvurun (bu ifade hem null hem de undefined değerlerini tek seferde yakalar).
Hepsini Bir Araya Getirelim
Tip dönüşümünün nerede işe yaradığını, nerede başınıza dert açtığını gösteren tam bir örnek:
İkinci çağrıya dikkat edin. Number("") size NaN değil, 0 döndürüyor — yani parsePrice("") çağrısı 0 sonucunu veriyor ve bu, fonksiyonu kullanan birinin muhtemelen beklediği davranış değil. Boş girdinin reddedilmesi gerekiyorsa, açık bir kontrol ekleyin:
Hangi değerlerin 0'a, hangilerinin NaN'e dönüştüğünü bilmek, ileride saatlerce süren sinsi hataların önüne geçmenizi sağlayan türden bir bilgidir.
Özetle Aklınızda Kalması Gerekenler
- Tip dönüşümü; operatöre bağlı olarak değeri string, number veya boolean'a çevirir.
+operatörü bir string ile kullanıldığında birleştirme (concatenation) yapar; diğer tüm aritmetik operatörler değeri sayıya zorlar.- Falsy değerler sabit ve kısa bir listedir — ezberleyin. Geri kalan her şey truthy'dir, buna
[]ve{}de dahil. Number("")sonucu0,Number([])sonucu0,Number(null)sonucu0'dır — amaNumber(undefined)sonucuNaN'dir. Bu detaylar gerçek projelerde bug olarak karşınıza çıkar.- Örtük (implicit) dönüşüm numaraları yerine
Number(x),String(x),Boolean(x)gibi açık (explicit) dönüşümleri tercih edin. Gelecekteki siz bunun için teşekkür edecek.
Sırada: Eşitlik Operatörleri
Karşılaştırmalardaki tüm bu tip dönüşümü hikâyesi aslında == operatörünün içinde yaşar. Bir sonraki sayfada == ile === ve Object.is arasındaki farkları, == operatörünün hâlâ işe yaradığı o tek kullanım kalıbını ve linter'ların neden varsayılan olarak gevşek eşitliği işaretlediğini inceleyeceğiz.
Sıkça Sorulan Sorular
JavaScript'te type coercion nedir?
Type coercion, JavaScript'in bir değeri otomatik olarak başka bir tipe dönüştürmesidir — sayının string'e, string'in sayıya ya da herhangi bir değerin boolean'a dönmesi gibi. +, == veya if gibi operatörler beklemedikleri bir tiple karşılaştığında implicit (örtük) olarak, siz Number(x), String(x) ya da Boolean(x) çağırdığınızda ise explicit (açık) olarak gerçekleşir.
Implicit ve explicit coercion arasındaki fark nedir?
Explicit coercion, dönüşümü bilerek yaptığınız durumdur: Number("42"), String(99), Boolean(value). Implicit coercion ise operatörün arka planda sessizce dönüşümü tetiklemesidir: "5" - 2 sonucu 3 verir ama "5" + 2 size "52" döner. Explicit olanı okuması kolay ve tahmin edilebilirdir; implicit olanı ise "bu neden NaN döndü ya" dediğiniz hataların ana kaynağıdır.
JavaScript'te string'i sayıya nasıl çeviririm?
Sıkı bir dönüşüm için Number("42") kullanın (geçerli bir sayı değilse NaN döner). Daha dağınık bir string'in başındaki sayıyı okumak istiyorsanız parseInt("42px", 10) veya parseFloat("3.14em") iş görür. Tekli + operatörü (+"42") de Number() ile aynı işi yapar ama koda hızlı göz gezdirirken gözden kaçması çok kolaydır.
[] + [] neden boş string döndürüyor?
[] + [] neden boş string döndürüyor?İki dizi için + operatörünün anlamlı bir sayısal işlemi yok, bu yüzden JavaScript ikisini de string'e çeviriyor. Diziler stringe dönerken elemanlarını virgülle birleştiriyor; boş dizi de "" oluyor. Yani [] + [] aslında "" + "" haline geliyor ve sonuç "" oluyor. Hoş bir parti numarası ama aynı zamanda + operatörünü primitive olmayan değerlerle kullanmamak için iyi bir sebep.