(NaN! = NaN) ve (NaN! == NaN) arasındaki fark nedir?


148

Her şeyden önce nasıl isNaN()ve Number.isNaN()çalıştığını bildiğimi belirtmek istiyorum . David Flanagan tarafından Kesin Rehber okuyorum ve o değerin olup olmadığını kontrol etmek için bir örnek verir NaN:

x !== x

Bu neden olacaktır trueancak ve ancak xolduğunu NaN.

Ama şimdi bir sorum var: neden sıkı karşılaştırma kullanıyor? Çünkü öyle görünüyor ki

x != x

aynı şekilde davranır. Her iki sürümleri kullanmaya, yoksa dönecektir JavaScript bazı değer (ler) Eksik güvenli mi trueiçin x !== xve falseiçin x != x?


10
Flanagan'ın !==kontrolleri !=kontrolleri tercih etmesi olabilir . Bildiğim kadarıyla nerede başka bir değeri yoktur x != x. Ancak iki farklı JavaScript geliştirici grubu vardır: hız, netlik, ifade vb. İçin !=tercih edenler ve tercih edenler!==
Steve Klösters

30
Sıkı karşılaştırma aynı şekilde davrandığında neden gevşek karşılaştırmayı kullanıyorsunuz?
Ry-

3
@Raulucco: NaNbenzersiz bir tür değil, bir sayı. Kendine eşit olmayan benzersiz bir değerdir .
TJ Crowder

8
Başlık insanları yanıltıcı görünüyor. Bunu "x! = X x! X == x? Den farklı mı?"
TJ Crowder

6
@femmestem: Giorgi "bu durumda" bunun bir stil meselesi olduğunu söyledi. Ve bu konuda haklı. O değil işlenen türleri farklı olduğunda tarzı, ama o olduğu aynı olduğunda stili. Ayrı: Flanagan bu karşılaştırmaların WTH yapıyor ===NaN ile noktayı NaN kendisine eşit olmadığını. "Yanlış" değil, bunu bir öğretme egzersizi olarak yapıyor ve işe yaramadığını gösteriyor.
TJ Crowder

Yanıtlar:


128

İlk olarak, NaNbunun çok özel bir değer olduğunu belirtmeme izin verin : Tanım olarak, kendisine eşit değildir. Bu, JavaScript numaralarının çizdiği IEEE-754 standardından gelir. "Bir sayı değil" değeri, bitler tam eşleşme olsa bile asla kendisiyle aynı değildir. (Bunlar mutlaka IEEE-754'te değil, birden fazla farklı "sayı değil" değerine izin verir.) Bu yüzden bu bile ortaya çıkıyor; JavaScript'teki diğer tüm değerler kendilerine eşittir NaN, sadece özeldir.

... JavaScript'te x! == x için true ve x! = x için false döndürecek bir değer eksik mi?

Hayır değilsin. Arasındaki tek fark !==ve !=aynı olacak şekilde operand tiplerini almak için gerekirse ikinci tip zorlama yapacak olmasıdır. İçinde x != x, işlenenlerin türleri aynıdır ve bu yüzden tam olarak aynıdır x !== x.

Bu Soyut Eşitlik Operasyonunun tanımının başlangıcından itibaren açıktır :

  1. ReturnIfAbrupt (x) tanımlanmaktadır.
  2. ReturnIfAbrupt (y).
  3. Tür (x), Tür (y) ile aynıysa,

    Sıkı Eşitlik Karşılaştırması yapmanın sonucunu döndürün x === y.

  4. ...

İlk iki adım temel tesisattır. Yani aslında, ilk adımı ==türlerin aynı olup olmadığını görmek ve eğer öyleyse ===bunun yerine yapmaktır . !=ve !==sadece olumsuzlanmış versiyonlarıdır.

Yani eğer Flanagan sadece bu doğru NaNiçin de geçerli verecektir x !== x, eminiz yalnızca o da doğru olabilir ki NaNiçin de geçerli verecektir x != x.

Birçok JavaScript programcısı , gevşek operatörlerin yaptığı tür zorlamasıyla ilgili bazı tuzakları kullanmaktan ===ve !==bunlardan kaçınmak için varsayılandır , ancak Flanagan'ın bu durumda katı ve gevşek operatörü kullanması hakkında okunacak hiçbir şey yoktur.


4.9.1 - Equality and Inequality OperatorsBölümü tekrar okudum ve bu cevap gibi görünüyor. İçin kilit nokta ===karşılaştırma geçerli: If the two values have the same type, test them for strict equality as described above. If they are strictly equal, they are equal. If they are not strictly equal, they are not equal.
Giorgi Nakeuri

@GiorgiNakeuri: Hangi 4.9.1'den bahsettiğinizden emin değilim, belki Flanagan'ın kitabından? Ama bu temelde yukarıdaki spesifikasyondan gelen teklifin ne dediğini söylüyor, evet.
TJ Crowder

2
Bunu kabul ediyorum çünkü bu sorumu resmileştirilmiş ve kesin bir şekilde cevaplıyor. Açıklamalar için teşekkürler!
Giorgi Nakeuri

1
@Moshe: "Canlı bağlantılar" ile ne demek istiyorsun? (Terim. Spec görünmez) sever ortalama bir şey yapın GOTO 0ın örneğin nerede aaslında bir fonksiyondur ve iki kez aynı değer döndürmez? Bu , OP'nin sorduğu doğru olan bir değerle aynı şey değildir !==. Bu sadece farklı değerler döndüren bir işlevdir. her çağrıda farklı değerler döndürebileceğinden foo() !== foo(), mutlaka doğru değildir foo.
TJ Crowder

1
@Moshe Bu özellik ve alıcılarla uğraşmanın süper kötü bir yoludur. Ancak, GOTO 0'ın örneğiyle hemen hemen aynı gibi görünüyor, sadece fazladan bir dolaylama katmanı ile.
JAB

37

NaN amaçları için, !=ve !==aynı şeyi yapın.

Ancak, birçok programcı JavaScript'ten kaçınır ==veya !=JavaScript kullanır. Örneğin, Douglas Crockford onları beklenmedik ve kafa karıştırıcı şekillerde davrandıkları için JavaScript dilinin " kötü bölümleri " arasında kabul eder :

: JavaScript iki eşitlik operatörleri setleri vardır ===ve !==ve onların kötü ikizler ==ve !=. İyi olanlar beklediğiniz gibi çalışır.

... Benim tavsiyem asla kötü ikizleri kullanmamak. Bunun yerine, her zaman ===ve kullanın !==.


2
Soru NaN ile ilgili değil (başlığa rağmen). Soru şu: "JavaScript'te x! == x için true, x! = X için false döndürecek bir değer eksik mi?"
TJ Crowder

@TJCrowder İki soru, gerçekten. İlk soru "Her iki sürümü de kullanmak güvenli midir" ve cevap her iki sürümün de eşdeğer olmasıdır. Her şeyi ayrıntılı olarak açıklayan "kaput altı" yanıtınızı beğeniyorum.
jkdev

22

Sadece eğlence için, nerede Sana yapay örnek yapalım xdeğil NaNama operatörler yine farklı davranır. İlk önce şunu tanımlayın:

Object.defineProperty(
  self,
  'x',
  { get: function() { return self.y = self.y ? 0 : '0'; } }
);

Sonra elimizde

x != x // false

fakat

x !== x // true

9
Ha! :-) Ama bu etkili bir şekilde foo() != foo()foo'nun 1'den sonra 2 değerini döndürdüğü yerdir. Örneğin, değerler aynı değil, sadece farklı değerleri karşılaştırıyor.
TJ Crowder

2

Sadece küresel nesneyi kullanmadan üretilen NaNtek şey olmadığını belirtmek istiyorum x !== x. Bu davranışı tetiklemenin birçok akıllı yolu vardır. İşte getters kullanan biri:

var i = 0, obj = { get x() { return i++; }};
with(obj) // force dynamic context, this is evil. 
console.log(x === x); // false

Diğer cevapların işaret ==ettiği gibi, tip tutarlılığını gerçekleştirir, ancak diğer dillerde olduğu gibi ve standardı eşitler - NaN bir hesaplama hatasını gösterir ve iyi nedenlerle kendine eşit değildir.

Bazı nedenlerden ötürü insanlar JS ile ilgili bir sorun olduğunu düşünüyorlar, ancak iki katına sahip çoğu dil (C, Java, C ++, C #, Python ve diğerleri) bu tam davranışı sergiliyor ve insanlar bununla iyi durumda.


2
Evet, @TJCrowder'ın GOTO_0'ın cevabına yaptığı yorumda tam olarak bahsettiği şey, değil mi?
Giorgi Nakeuri

Bu diğer dillerde belirsiz tip baskıyı nasıl elde edebileceğinizi açıklayabilir misiniz?
chicocvenancio

0

Bazen, görüntüler kelimelerden daha iyidir, bu tabloyu kontrol edin (bu bir yorum yapmamın sebebi, bunun yerine bir yorum yapmamın nedeni, daha iyi görünürlük elde etmesidir).

Burada katı eşitlik karşılaştırmasının (===) yalnızca tür ve içerik eşleştiğinde doğru döndüğünü görebilirsiniz.

var f = "-1" === -1; //false

Soyut eşitlik karşılaştırması (==), türleri dönüştürerek ve sonra bunları kesinlikle karşılaştırarak yalnızca içeriği * kontrol eder:

var t = "-1" == -1; //true

Her ne kadar net olmasa da, ECMA'ya danışmadan , JavaScript'in karşılaştırırken ne düşündüğü, aşağıdaki kod doğru olarak değerlendirilir.

 var howAmISupposedToKnowThat = [] == false; //true
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.