parseInt (null, 24) === 23… bekle, ne?


226

Tamam, bu yüzden henüz başlatılmamış değerleri nasıl işlediğini görmek için parseInt ile uğraşıyordum ve bu gem tökezledi. Aşağıdakiler 24 veya daha büyük herhangi bir sayı için olur.

parseInt(null, 24) === 23 // evaluates to true

IE, Chrome ve Firefox'ta test ettim ve hepsi doğru uyarıyor, bu yüzden bir yerlerde spesifikasyonda olması gerektiğini düşünüyorum. Hızlı bir Google araması bana herhangi bir sonuç vermedi, bu yüzden buradayım, birinin açıklayabileceğini umuyorum.

typeof null === "object"Object ve Null'un bellekte neredeyse aynı tip tanımlayıcıya veya bu satırlar boyunca bir şeye sahip olmasına neden olan bir gözetim nedeniyle söylediği bir Crockford konuşmasını dinlediğimi hatırlıyorum , ancak şimdi bu videoyu bulamıyorum.

Deneyin: http://jsfiddle.net/robert/txjwP/

Düzeltmeyi Düzenle : daha yüksek bir yarıçap farklı sonuçlar döndürür, 32 döndürür 785077 2'yi
Düzenle zzzzBov'dan:[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


tl; Dr.

Neden parseInt(null, 24) === 23gerçek bir ifade olduğunu açıklayın .


49
Ne tuhaf. JavaScript sizi her zaman elinizin altında tutar.
FishBasketGordo

1
Veri noktası: alert(parseInt(null, 34) === 23)üretilmişfalse
Stephen P

1
alert(parseInt(null,26)===23);ayrıca doğru üretir?!?!
Petar Ivanov

6
[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745,[37...]:NaN
zzzzBov

1
Ek bir not undefinedolarak, ilk parametre
30'lar

Yanıtlar:


240

Bu çeviriyor nulldizeye "null"ve dönüştürmek için çalışıyor. 0 ile 23 arasındaki çaplar için, dönüştürebileceği hiçbir sayı yoktur, bu yüzden geri döner NaN. 24 yaşında "n", 14. harf, sayı sistemine eklenir. 31'de, "u"21. harf eklenir ve tüm dizginin kodu çözülebilir. 37'de artık üretilebilecek geçerli bir sayısal küme yoktur ve NaN döndürülür.

js> parseInt(null, 36)
1112745

>>> reduce(lambda x, y: x * 36 + y, [(string.digits + string.lowercase).index(x) for x in 'null'])
1112745

3
@Tomalak: Kim kullandığını söylüyor toString()?
Ignacio Vazquez-Abrams

3
@Ignacio. Aslında yanılmışım. 37'nin bir sayıya atıfta bulunduğunu anlamıyordum. Bunun için üzgünüm.
Mike Samuel

3
@ Robert, hayır kafam karıştı ve iddia ettiği şeyden başka bir şey iddia ettiğini düşündüm. Doğru cevap bu. Her yerde özür dilerim.
Mike Samuel

19
Hala bu cevabın bazı referanslarla yapılabileceğini düşünüyorum. Tamamen doğru olmasına rağmen, gerçekten sadece büyük bir iddia ...
Orbit'te Hafiflik Yarışları

4
@Tomalak - tüm referanslar için cevabımı kontrol et. Bu cevap doğru (ve önce) cevaptır, bu yüzden kabul edilen cevap olarak kalması gerektiğini düşünüyorum. Kaputun altında neler olduğunu açıklamak asla
acıtsa da

118

Mozilla bize şunları söylüyor :

function parseInt ilk bağımsız değişkenini bir dizeye dönüştürür , ayrıştırır ve bir tam sayı veya NaN döndürür. NaN değilse, döndürülen değer, belirtilen yarıçapta (taban) sayı olarak alınan ilk bağımsız değişkenin ondalık tamsayısı temsilidir. Örneğin, 10'luk bir yarıçap ondalık sayı, 8 sekizlik, 16 onaltılık ve benzeri sayıdan dönüştürüleceğini belirtir. 10'un üzerindeki radyasyonlar için, alfabedeki harfler 9'dan büyük rakamları gösterir. Örneğin, onaltılık sayılar (taban 16) için A'dan F'ye kadar kullanılır.

In spec , 15.1.2.2/1 dizeye dönüştürme kullanarak yerine getirildiği yerleşik söyler ToString(9.8 uyarınca) verimleri olan "null"(ile karıştırılmamalıdır toStringdoğuracak olan, "[object Window]"!).

Şimdi düşünelim parseInt("null", 24).

Tabii ki, bu tamamen bir base-24 sayısal dizesi değil, ama "n": ondalık 23 .

Şimdi, ayrıştırma çünkü ondalık 23 dışarıya çekildikten sonra durur "u" değildir taban-24 sisteminde bulunan:

S, sayı tabanı R karakteri olmayan herhangi bir karakter içeriyorsa, Z'nin bu tür ilk karakterden önceki tüm karakterlerden oluşan S'nin alt dizesi olmasına izin verin; aksi halde Z olsun. S [15.1.2.2/11]

(Ve bu yüzden parseInt(null, 23)(ve daha düşük radyasyonlar) NaN23 yerine size verir : 23 "n"taban sisteminde değildir.)


2
Bu parseInt'in çok trajik davranışıdır (bu durumda istisna olsa da neden tasarım olmadığını düşünüyordum). Yapabileceğim zaman bunun yerine NUMBER () kullanmayı tercih ederim.
Grijesh Chauhan

79

Ignacio Vazquez-Abrams doğru, ama tam olarak nasıl çalıştığını görelim ...

Gönderen 15.1.2.2 parseInt (string , radix):

ParseInt işlevi çağrıldığında aşağıdaki adımlar atılır:

  • İnputString öğesinin ToString (string) olmasına izin verin.
  • S, StrWhiteSpaceChar olmayan ilk karakterden ve bu karakteri izleyen tüm karakterlerden oluşan inputString'in yeni oluşturulan bir alt dizesi olsun. (Başka bir deyişle, önde gelen beyaz boşluğu kaldırın.)
  • İşaret 1 olsun.
  • S boş değilse ve S'nin ilk karakteri eksi işaretiyse - işareti −1 olsun.
  • S boş değilse ve S'nin ilk karakteri artı işareti + veya eksi işareti - ise, ilk karakteri S'den kaldırın.
  • R = ToInt32 (sayı tabanı) olsun.
  • StripPrefix öğesinin true olmasına izin verin.
  • R ≠ 0 ise, a. R2 veya R36 ise, NaN değerini döndürün. b. R ≠ 16 ise, stripPrefix öğesinin false olmasına izin verin.
  • Else, R = 0 a. R = 10 olsun.
  • StripPrefix doğruysa, a. S uzunluğu en az 2 ise ve S'nin ilk iki karakteri “0x” veya “0X” ise, ilk iki karakteri S'den kaldırın ve R = 16 olsun.
  • S, sayı tabanı R karakteri olmayan herhangi bir karakter içeriyorsa, Z'nin bu tür ilk karakterden önceki tüm karakterlerden oluşan S'nin alt dizesi olmasına izin verin; Aksi takdirde, Z'nin S olmasına izin verin.
  • Z boşsa, NaN'yi iade edin.
  • 10 ila 35 arası değerlere sahip basamaklar için AZ ve az harflerini kullanarak, radix-R göstergesinde Z ile temsil edilen matematiksel tamsayı değeri olsun. (Ancak, R 10 ise ve Z, 20'den fazla önemli basamak içeriyorsa, 20'den sonraki rakam, uygulama seçeneğinde 0 rakamıyla değiştirilebilir ve R 2, 4, 8, 10, 16 veya 32 değilse, mathInt, matematiksel tamsayıya uygulamaya bağlı bir yaklaşım olabilir. radix-R gösterimlerinde Z ile temsil edilen değer.)
  • Sayının mathInt için Number değeri olmasına izin verin.
  • Dönüş işareti × sayı.

NOT parseInt, dizenin yalnızca önde gelen bir kısmını bir tamsayı değeri olarak yorumlayabilir; bir tamsayı gösteriminin bir parçası olarak yorumlanamayan karakterleri yok sayar ve bu karakterlerin yok sayıldığına dair herhangi bir işaret verilmez.

Burada iki önemli kısım var. İkisini de cüret ettim. Bu yüzden her şeyden önce, toStringtemsilinin ne olduğunu bulmalıyız null. Bu Table 13 — ToString Conversionsbilgi için bölüm 9.8.0'a bakmamız gerekir :

resim açıklamasını buraya girin

Harika, şimdi toString(null)dahili olarak yapmanın bir 'null'ip verdiğini biliyoruz . Harika, ancak sağlanan yarıçapta geçerli olmayan rakamları (karakterleri) tam olarak nasıl ele alıyor?

Yukarıya bakarız 15.1.2.2ve aşağıdaki ifadeyi görürüz:

S, sayı tabanı R karakteri olmayan herhangi bir karakter içeriyorsa, Z'nin bu tür ilk karakterden önceki tüm karakterlerden oluşan S'nin alt dizesi olmasına izin verin; Aksi takdirde, Z'nin S olmasına izin verin.

Bu, tüm sayıları ÖNCE belirtilen sayıdaki çapa göre işlediğimiz ve diğer her şeyi göz ardı ettiğimiz anlamına gelir.

Temel olarak, yapmak parseInt(null, 23)aynı şeydir parseInt('null', 23). uİki neden l(onlar radix 23 parçası OLAN olsa bile) 'göz ardı etmek bu. Bu nedenle, yalnızca ayrıştırıp ntüm ifadeyi eş anlamlı hale getirebiliriz parseInt('n', 23). :)

Her iki durumda da harika bir soru!


33
parseInt( null, 24 ) === 23

Eşittir

parseInt( String(null), 24 ) === 23

eşdeğer

parseInt( "null", 24 ) === 23

Taban 24 için basamaklar 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, ..., n'dir.

Spec'in söylediği

  1. S, sayı tabanı R karakteri olmayan herhangi bir karakter içeriyorsa, Z'nin bu tür ilk karakterden önceki tüm karakterlerden oluşan S'nin alt dizesi olmasına izin verin; Aksi takdirde, Z'nin S olmasına izin verin.

C-tarzı tamsayı değişmez değerlerinin 15Ldüzgün ayrıştırmayı sevmesini sağlayan kısımdır , bu nedenle yukarıdakiler

parseInt( "n", 24 ) === 23

"n" yukarıdaki rakam listesinin 23. harfidir.

QED


16

Sanırım nullbir dizeye dönüştürülür "null". Yani naslında 23'base24' ('base25' + 'da), u' base24 'içinde geçersizdir, bu nedenle dizenin geri kalanı nullyoksayılır. Bu yüzden 'base31' de geçerli 23olana kadar çıktı u.


7

parseInt alfasayısal temsili kullanır, sonra taban-24 "n" de geçerlidir, ancak "u" geçersiz karakterdir, daha sonra parseInt yalnızca "n" değerini ayrıştırır ....

parseInt("n",24) -> 23

örnek olarak şunu deneyin:

alert(parseInt("3x", 24))

Sonuç "3" olur.

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.