İçeriğe geç
academia.sh

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:

  1. Tipler aynıysa katı eşitlik uygulanır.
  2. Bir yan null, diğeri undefined ise sonuç doğrudur. Bu ikisi başka hiçbir değere gevşek eşit değildir.
  3. Bir yan sayı, diğeri dizgi ise dizgi sayıya çevrilir.
  4. Bir yan mantıksal değer ise önce o yan sayıya çevrilir, sonra kurallar yeniden uygulanır.
  5. 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: a=ba = b ve b=cb = c ise a=ca = c 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ğerin null veya undefined olup olmadığını birlikte sınayan deger == null yazı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.
  • NaN hiçbir değere, kendisine bile eşit değildir; 0 ile -0 katı eşitlikte eşittir.
  • == beş kuralla ortak tipe iner; null ve undefined yalnı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 istisna deger == null yazımıdır.
  • Object.is değer eşitliğidir: NaN kendisine eşit, 0 ile -0 farklı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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat