Ders 09 / 21
Eşitlik Karşılaştırmaları
Katı eşitlik, gevşek eşitliğin adım adım algoritması, değer eşitliği ve nesnelerde kimlik karşılaştırması.
İçindekiler
Önceki ders zorlama yordamlarını tanımladı: bir değerin sayıya, metne ve ilkel değere nasıl çevrildiğini. Bu ders o yordamların en çok kullanıldığı yeri ele alır. JavaScript’te iki değeri karşılaştırmanın üç ayrı yolu vardır ve üçü farklı sorulara yanıt verir.
Üçü de tek bir eksende ayrışır: karşılaştırmadan önce zorlama uygulanıyor mu, ve özel
sayı değerleri (NaN, -0) nasıl ele alınıyor. Ayrımı bilmek, “neden eşit çıktı”
sorusunu tahminden çıkarıp adım takibine dönüştürür.
Katı Eşitlik
=== işleci önce tipe bakar. Tipler farklıysa sonuç doğrudan yanlıştır; zorlama
yapılmaz. Tipler aynıysa değerler karşılaştırılır.
console.log(21.5 === 21.5); console.log("A1" === "A1"); console.log(1 === "1"); console.log(NaN === NaN); console.log(0 === -0);
true true false false true
Üçüncü satır tip farkından yanlış verdi. Son iki satır ise sayı tipine özgü iki
istisnadır ve ikisi de IEEE 754 gösteriminden gelir. NaN, kendisi dahil hiçbir değere
eşit değildir; standart bunu açıkça yazar. İşaretli sıfırlar ise farklı bit örüntüleri
olmasına rağmen eşit sayılır.
NaN’ın kendine eşit olmaması, bir değerin NaN olup olmadığını eşitlikle sınamayı
imkânsız kılar. Bunun için ayrı bir yoklama vardır:
console.log(Number.isNaN(NaN)); console.log(Number.isNaN("abc")); console.log(isNaN("abc"));
true false true
İki yoklamanın farkı önemlidir. Number.isNaN, değerin sayı tipinde ve NaN olmasını
ister. Genel yoklama ise argümanı önce sayıya çevirir; "abc" metni NaN’a çevrildiği
için doğru verir. İkincisi “bu değer sayıya çevrilemiyor” sorusunu yanıtlar, birincisi
“bu değer NaN mı” sorusunu. Kursta yalnızca birincisi kullanılacaktır.
Gevşek Eşitlik
== işleci, tipler farklıysa zorlama uygulayarak ortak bir tipe iner. Adımları
standartta sırayla tanımlıdır ve pratikte şu beş kural yeterlidir:
- Tipler aynıysa katı eşitlik uygulanır.
- Bir yan
null, diğeriundefinedise sonuç doğrudur. Bu ikisi başka hiçbir değere gevşek eşit değildir. - Bir yan sayı, diğeri dizgi ise dizgi sayıya çevrilir.
- Bir yan mantıksal değer ise önce o yan sayıya çevrilir, sonra kurallar yeniden uygulanır.
- Bir yan nesne, diğeri ilkel ise nesne ilkel değere çevrilir ve kurallar yeniden uygulanır.
Kuralların sonuçları:
console.log(null == undefined); console.log(null == 0, undefined == 0); console.log("1" == 1); console.log("" == 0); console.log("0" == 0); console.log("" == "0");
true false false true true true false
İkinci satır ikinci kuralın doğrudan sonucudur: null, sayıya çevrilmez; yalnızca
undefined ile eşleşir. Bu, null denetimini gevşek eşitlikle yazmayı güvenli kılan tek
davranıştır.
Mantıksal değer kuralı sezgiye en aykırı sonuçları üretir:
console.log(true == 1, true == "1", false == ""); console.log([] == false); console.log([21.5] == 21.5); console.log([1, 2] == "1,2");
true true true true true true
Dördüncü satırı adım adım okumak yöntemi gösterir. [] == false ifadesinde önce dördüncü
kural uygulanır: false sayıya çevrilir, 0 olur. Şimdi bir yan nesne, diğeri sayıdır;
beşinci kural gereği dizi ilkel değere çevrilir ve boş metin olur. Son adımda üçüncü
kural boş metni sayıya çevirir; sonuç 0 == 0 olur ve doğru çıkar. Hiçbir adım keyfi
değildir.
Gevşek Eşitlik Geçişli Değildir
Bir eşitlik bağıntısından beklenen özelliklerden biri geçişliliktir: ve ise olmalıdır. Gevşek eşitlik bu özelliği taşımaz:
console.log("0" == 0); console.log(0 == ""); console.log("0" == "");
true true false
İlk iki satırda karşılaştırma sayı üzerinden yapıldı; üçüncü satırda iki yan da dizgi olduğu için birinci kural devreye girdi ve zorlama olmadı. Sonuç, birbiriyle çelişmeyen ama geçişli olmayan bir bağıntıdır.
Buradan kursun kuralı çıkar:
Eşitlik karşılaştırmaları
===ile yazılır. Tek istisna, bir değerinnullveyaundefinedolup olmadığını birlikte sınayandeger == nullyazımıdır.
İstisnanın gerekçesi ikinci kuraldır: bu yazım tam olarak iki değeri kapsar, başka hiçbir değeri yanlışlıkla içine almaz.
const gelen = { istasyon: "A2", nem: undefined }; console.log("gevsek:", gelen.nem == null); console.log("kati :", gelen.nem === null);
gevsek: true kati : false
İki satır farklı soruları yanıtlıyor. Birincisi “bu alanın değeri yok mu”; ikincisi “bu alan bilinçli olarak boş mu”. İlkel Tipler dersindeki ayrım hangi soruyu sormak gerektiğini belirler.
Değer Eşitliği
Üçüncü yol, katı eşitliğin iki istisnasını da ortadan kaldırır:
console.log(Object.is(NaN, NaN)); console.log(Object.is(0, -0)); console.log(Object.is(21.5, 21.5));
true false true
Object.is, iki değerin aynı değer olup olmadığını sorar. NaN kendisiyle aynı
değerdir; 0 ile -0 farklı değerlerdir. Bu, standardın birkaç yerinde iç karşılaştırma
olarak kullanılan bağıntıdır.
Günlük kullanımda Object.is gerekmez; === ile Number.isNaN birlikte aynı işi görür
ve daha okunaklıdır. Ayrımı bilmek, yerleşik yöntemlerin davranışını açıklamak için
gereklidir — örneğin dizi arama yöntemlerinin bir kısmı NaN bulabilirken bir kısmı
bulamaz, çünkü farklı bağıntılar kullanırlar.
Nesnelerde Karşılaştırma
Üç işlecin hiçbiri nesne içeriğini karşılaştırmaz. Nesneler için karşılaştırılan şey kimliktir: iki başvurunun aynı nesneyi gösterip göstermediği.
const a = { istasyon: "A1" }; const b = { istasyon: "A1" }; const c = a; console.log(a === b); console.log(a === c); console.log(a == b);
false true false
a ile b aynı içeriğe sahiptir ama farklı nesnelerdir. c, a ile aynı nesneyi
gösterdiği için eşittir. Gevşek eşitlik de aynı sonucu verir: iki yan da nesne olduğu
için birinci kural devreye girer ve zorlama yapılmaz.
Programlama Temelleri kursundaki Değişkenler ve Bağlama dersinde kurulan kimlik–eşitlik ayrımı burada dilin işleçlerine birebir yansımıştır. İçerik karşılaştırması gerekiyorsa yazılması gerekir; dil bunu sağlamaz.
Ölçüm Betiğine Uygulama
Kayıtların geçerliliğini sınayan denetimler, doğru işleçle yazıldığında hem eksik hem bozuk alanları ayırt eder:
const kayitlar = [ { istasyon: "A1", sicaklik: 21.5, nem: null }, { istasyon: "A2", sicaklik: 0, nem: 55 }, { istasyon: "B1", sicaklik: NaN, nem: 41 }, ]; for (const k of kayitlar) { const nemEksik = k.nem == null; const sicaklikGecersiz = Number.isNaN(k.sicaklik); console.log(k.istasyon, "nem eksik:", nemEksik, "sicaklik gecersiz:", sicaklikGecersiz); }
A1 nem eksik: true sicaklik gecersiz: false A2 nem eksik: false sicaklik gecersiz: false B1 nem eksik: false sicaklik gecersiz: true
İkinci kayıttaki 0 değeri her iki denetimden de geçti — sıfır, ne eksik ne geçersizdir.
Bir önceki derste kısayol yazımının bozduğu tam olarak bu durumdu. Üçüncü kayıttaki NaN
ise yalnızca Number.isNaN ile yakalanabilir; k.sicaklik === NaN yazımı hiçbir zaman
doğru vermezdi.
Özet
===önce tipe bakar; tipler farklıysa zorlama yapmadan yanlış verir.NaNhiçbir değere, kendisine bile eşit değildir;0ile-0katı eşitlikte eşittir.==beş kuralla ortak tipe iner;nullveundefinedyalnızca birbirine eşittir, mantıksal değerler önce sayıya çevrilir, nesneler ilkel değere indirgenir.- Gevşek eşitlik geçişli değildir; bu yüzden karşılaştırmalar
===ile yazılır, tek istisnadeger == nullyazımıdır. Object.isdeğer eşitliğidir:NaNkendisine eşit,0ile-0farklıdır.- Nesneler kimliğe göre karşılaştırılır; içerik karşılaştırması yazılmadıkça yapılmaz.
Sonraki Adım
Önceki derste bırakılan soru hâlâ açık: koşulun içine sayı, dizgi veya nesne konduğunda
ne olur? if (deger) yazımı bir eşitlik karşılaştırması değildir; değeri mantıksal tipe
çeviren üçüncü zorlama yordamını çağırır. Sonraki ders bu yordamın tam listesini verecek
ve 0 değerinin neden eksik veri sanıldığını gösterecek.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.