parseInt(null、24)=== 23…待って、何?


226

了解しました。それで、parseIntをいじって、まだ初期化されていない値を処理する方法を確認していたところ、このgemを偶然見つけました。以下は、基数24以上で発生します。

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

私はそれをIE、Chrome、Firefoxでテストしましたが、すべてがtrueであることを警告しているので、仕様のどこかにあるはずだと思います。Googleをすばやく検索しても結果は得られなかったので、ここで私は誰かが説明してくれることを望んでいます。

typeof null === "object"見落としが原因でObjectとNullがメモリ内のほぼ同じ型識別子またはそれらに沿った何かを持っているために彼が言っていたCrockfordのスピーチを聞いたことを覚えていますが、今はそのビデオを見つけることができません。

試してみてください:http : //jsfiddle.net/robert/txjwP/

編集の修正:基数が大きいと異なる結果が返され、32の場合は785077が返されます
編集2 zzzzBovから:[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


tl; dr

parseInt(null, 24) === 23が真の声明である理由を説明してください。


49
なんて変わった。JavaScriptは常にあなたをつま先に保ちます。
FishBasketGordo

1
データポイント:alert(parseInt(null, 34) === 23)作成済みfalse
スティーブンP

1
alert(parseInt(null,26)===23);また、真の?!?!
Petar Ivanov

6
[24...30]:2331:71469532:78507733:85993534:93940735:102363136:1112745[37...]:NaN
zzzzBov

1
追加の注記undefinedとして、最初のパラメーターが30代の奇妙な結果を返すため
zzzzBov

回答:


240

これは、変換だnull文字列に"null"し、それを変換しようとしています。基数0〜23の場合、変換できる数値がないため、を返しますNaN。24で"n"、14番目の文字が数値システムに追加されます。31で、"u"、21日の手紙は、追加され、文字列全体を復号することができます。37では、生成できる有効な数値セットがなくなり、NaNが返されます。

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:使用していると誰が言うのtoString()ですか?
Ignacio Vazquez-Abrams

3
@Ignacio。実際、私は間違っていました。37が基数を参照していることに気付きませんでした。申し訳ありません。
マイクサミュエル

3
@ロバート、私は混乱せず、彼が主張しているもの以外の何かを主張していると思いました。それが正解です。周りに謝罪。
マイクサミュエル

19
この答えはいくつかの参考文献でうまくいくと私はまだ考えています。それは完全に正しいですが、それは本当に1つの大きな主張です...
オービットのライトネスレース

4
@Tomalak-すべての参照について私の答えを確認してください。この答えは正しい(そして最初の)答えなので、受け入れられたままにしておくべきだと思います。フードの下で何が起こっているかを説明するのは決して

118

Mozilla は私たちに言っています:

関数parseIntは、最初の引数を文字列変換し、それを解析して、整数またはNaNを返します。NaNでない場合、戻り値は、指定された基数(基数)の数値としてとられた最初の引数の10進整数表現になります。たとえば、基数が10の場合、10進数、8進数で8、16進数で16などに変換されます。10を超える基数の場合、アルファベットの文字は9より大きい数値を示します。たとえば、16進数(基数16)の場合、A〜Fが使用されます。

ではスペック、15.1.2.2/1は、文字列への変換は、内蔵使用して実行されていることを告げToStringた(9.8による)利回り、"null"(と混同しないでtoString生じるであろう、"[object Window]"!)。

では、考えてみましょうparseInt("null", 24)

もちろん、これは全体として24 進数の文字列ではありませんが、「n」は10進数の23です。

10進数の23が引き出された後、base-24システムに"u" はないため、解析が停止します。

Sに基数Rの数字ではない文字が含まれている場合、Zを最初のそのような文字の前のすべての文字で構成されるSの部分文字列とします。それ以外の場合は、ZをSとします。[15.1.2.2/11]

(そして、これが(そしてparseInt(null, 23)より低い基数)がNaN23ではなくあなたに与える理由です:"n"base-23システムにはありません。)


2
これはparseIntの非常に悲劇的な振る舞いです(私はなぜこれらが例外であるにもかかわらず設計されていないのかを考えていました)。可能な場合は代わりにNUMBER()を使用したいと思います。
Grijesh Chauhan 14年

79

イグナシオバスケスエイブラムスは正しいですが、それがどのように機能するかを正確に確認できます...

から15.1.2.2 parseInt (string , radix)

parseInt関数が呼び出されると、次の手順が実行されます。

  • inputStringをToString(string)とします。
  • Sを、StrWhiteSpaceCharではない最初の文字と、その文字に続くすべての文字で構成されるinputStringの新しく作成された部分文字列とします。(つまり、先頭の空白を削除します。)
  • 符号を1とします。
  • Sが空でなく、Sの最初の文字がマイナス記号-の場合、記号を-1とします。
  • Sが空でなく、Sの最初の文字がプラス記号+またはマイナス記号-の場合、Sから最初の文字を削除します。
  • R = ToInt32(radix)とします。
  • stripPrefixをtrueにします。
  • R≠0の場合、a。R <2またはR> 36の場合、NaNを返します。b。R≠16の場合、stripPrefixをfalseにします。
  • そうでなければ、R = 0 a。R = 10とします。
  • stripPrefixがtrueの場合、a。Sの長さが2以上で、Sの最初の2文字が「0x」または「0X」の場合、Sから最初の2文字を削除し、R = 16にします。
  • Sに基数Rの数字ではない文字が含まれている場合、Zを最初のそのような文字の前のすべての文字で構成されるSの部分文字列とします。それ以外の場合は、ZをSとします。
  • Zが空の場合、NaNを返します。
  • mathIntを、基数R表記でZによって表される数学的整数値とし、値10〜35の数字に文字AZおよびazを使用します。 20番目以降の数字は、実装のオプションで0の数字に置き換えることができます。Rが2、4、8、10、16、または32でない場合、mathIntは、実装に依存する数学的な整数の近似値になります。基数R表記でZで表される値。)
  • numberをmathIntのNumber値とします。
  • リターンサイン×ナンバー。

注parseIntは、文字列の先頭部分のみを整数値として解釈する場合があります。整数の表記の一部として解釈できない文字は無視され、そのような文字が無視されたという表示はありません。

ここには2つの重要な部分があります。どちらも太字にしました。だからまず、何のtoString表現かを見つけなければなりませんnullTable 13 — ToString Conversionsその情報については、セクション9.8.0 を確認する必要があります。

ここに画像の説明を入力してください

すばらしいので、これでtoString(null)内部的に'null'文字列が生成されることがわかりました。すばらしいですが、指定された基数内で無効な数字(文字)をどのように正確に処理しますか?

15.1.2.2を見ると、次のコメントがあります。

Sに基数Rの数字ではない文字が含まれている場合、Zを最初のそのような文字の前のすべての文字で構成されるSの部分文字列とします。それ以外の場合は、ZをSとします。

つまり、指定された基数より前のすべての数字を処理し、その他はすべて無視します。

基本的に、行うことparseInt(null, 23)はと同じことparseInt('null', 23)です。これuにより、2つlのは無視されます(ただし、基数23の一部であっても)。したがって、解析のみが可能でnあり、ステートメント全体がと同義になりparseInt('n', 23)ます。:)

どちらにしても、すばらしい質問です。


33
parseInt( null, 24 ) === 23

に相当

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

これは

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

基数24の数字は0、1、2、3、4、5、6、7、8、9、a、b、c、d、e、f、...、nです。

言語仕様は言う

  1. Sに基数Rの数字ではない文字が含まれている場合、Zを最初のそのような文字の前のすべての文字で構成されるSの部分文字列とします。それ以外の場合は、ZをSとします。

これは、Cスタイルの整数リテラルが15L適切に解析されることを保証する部分であるため、上記は次と同等です。

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

"n" 上記の数字リストの23番目の文字です。

QED


16

null文字列に変換されると思います"null"。したがってn、実際に23は 'base24'( 'base25' +でも同じ)にuあり、 'base24'では無効であるため、残りの文字列nullは無視されます。そのため、「base31」で有効になる23まで出力しますu


7

parseIntは英数字表現を使用し、base-24では「n」は有効ですが、「u」は無効な文字であり、parseIntは値「n」のみを解析します。

parseInt("n",24) -> 23

例として、これで試してください:

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

結果は「3」になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.