parseInt (null, 24) === 23… чекай, що?


226

Гаразд, тому я заплутався з parseInt, щоб побачити, як він обробляє значення, ще не ініціалізовані, і я натрапив на цей дорогоцінний камінь. Нижче відбувається для будь-якого радіусу 24 або вище.

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

Я перевірив його в IE, Chrome і Firefox, і всі вони попереджають вірно, тому я думаю, що він десь повинен бути в специфікації. Швидкий пошук Google не дав мені жодних результатів, тож ось я, сподіваючись, хтось може пояснити.

Я пам’ятаю, як слухав виступ Крокфорда, де він говорив typeof null === "object"через недогляд, через який у Object and Null є майже однаковий ідентифікатор типу в пам’яті або щось подібне, але я не можу знайти це відео зараз.

Спробуйте: http://jsfiddle.net/robert/txjwP/

Редагувати Виправлення: вища радікс повертає різні результати, 32 повертає 785077
редагувати 2 З zzzzBov:[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


тл; д-р

Поясніть, чому parseInt(null, 24) === 23це правдиве твердження.


49
Як вигадливий. JavaScript завжди тримає вас на ногах.
FishBasketGordo

1
Точка даних: alert(parseInt(null, 34) === 23)створеноfalse
Стівен П

1
alert(parseInt(null,26)===23);також виробляє справжнє?!?!
Петро Іванов

6
[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36: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()?
Ігнасіо Васкес-Абрамс

3
@Ignacio. Насправді я помилявся. Я не усвідомлював, що 37 має на увазі радіацію. Вибач за це.
Майк Самуель

3
@Robert, ні, я не розгубився і подумав, що він вимагає чогось іншого, ніж те, що він вимагає. Це правильна відповідь. Вибачте все навколо.
Майк Самуель

19
Я все ще думаю, що ця відповідь могла б мати деякі посилання. Хоча це цілком правильно, це дійсно лише одне велике твердження ...
Гонки легкості в Орбіті

4
@Tomalak - перевіри мою відповідь на всі посилання. Ця відповідь є правильною (і першою), тому я думаю, що вона повинна залишатися прийнятою. Хоча ніколи не боляче пояснювати, що відбувається під капотом;)
Девід Тітаренко

118

Mozilla каже нам :

функція parseInt перетворює свій перший аргумент у рядок , аналізує його і повертає ціле число або NaN. Якщо немає NaN, поверненим значенням буде десятичне ціле представлення першого аргументу, прийнятого як число у вказаному радіусі (базі). Наприклад, радіус 10 вказує на перетворення з десяткового числа, 8 вісімкових, 16 шістнадцяткових тощо. Для радикусів вище 10 букви алфавіту вказують цифри, більші за 9. Наприклад, для шістнадцяткових чисел (основа 16) використовуються від A до F.

У специфікації 15.1.2.2/1 йдеться про те, що перетворення в рядок здійснюється за допомогою вбудованого модуля ToString, який (відповідно до 9.8) дає результат "null"(не плутати з цим toString, що дасть результат "[object Window]"!).

Отже, давайте розглянемо parseInt("null", 24).

Звичайно, це не числовий рядок базової 24 в цілому, але "n" є: це десяткова 23 .

Тепер розбір зупиняється після виведення десяткових 23, оскільки "u" його немає в системі base-24:

Якщо S містить будь-який символ, який не є цифрою Rx, R, то нехай Z є підрядком S, що складається з усіх символів перед першим таким символом; інакше нехай Z буде S. [15.1.2.2/11]

(І саме тому parseInt(null, 23)(і нижчі радикуси) дає вам NaNшвидше 23: "n"немає в системі base-23.)


2
Це дуже трагічна поведінка parseInt (я думав, чому це не задумано, хоча в цьому випадку є винятком). Я вважаю за краще використовувати NUMBER () замість цього, коли можу.
Grijesh Chauhan

79

Ігнасіо Васкес-Абрамс правильний, але давайте побачимо, як саме це працює ...

Від 15.1.2.2 parseInt (string , radix):

Коли викликається функція parseInt, виконуються наступні кроки:

  • Нехай inputString буде ToString (рядок).
  • Нехай S - новостворена підрядка inputString, що складається з першого символу, який не є StrWhiteSpaceChar, та всіх символів, що слідують за цим символом. (Іншими словами, видаліть провідний пробіл.)
  • Нехай знак буде 1.
  • Якщо S не порожній, а перший символ S - знак мінус -, нехай знак буде -1.
  • Якщо S не порожній, а перший символ S - знак плюс + або мінус -, тоді видаліть перший символ із S.
  • Нехай R = ToInt32 (радікс).
  • Нехай stripPrefix є істинним.
  • Якщо R ≠ 0, то a. Якщо R <2 або R> 36, то поверніть NaN. б. Якщо R ≠ 16, нехай falsePrefix буде хибним.
  • Інше, R = 0 а. Нехай R = 10.
  • Якщо stripPrefix вірно, то a. Якщо довжина S становить щонайменше 2, а перші два символи S або "0x", або "0X", тоді видаліть з S перші два символи та нехай R = 16.
  • Якщо S містить будь-який символ, який не є цифрою Rx, R, то нехай Z є підрядком S, що складається з усіх символів перед першим таким символом; інакше нехай Z буде S.
  • Якщо Z порожній, поверніть NaN.
  • Нехай mathInt - це значення математичного цілого числа, яке представлено Z у позначенні radix-R, використовуючи букви AZ та az для цифр зі значеннями 10 - 35. (Однак, якщо R 10 і Z містить більше 20 значущих цифр, кожна значна цифра після 20-ї може бути замінена на 0 цифри за вибором реалізації; а якщо R не 2, 4, 8, 10, 16 або 32, то mathInt може бути наближеним до впровадження математичним цілим числом значення, яке представлено Z у позначенні радікс-R.)
  • Нехай число є значенням числа для mathInt.
  • Зворотний знак × номер.

ПРИМІТКА parseInt може інтерпретувати лише провідну частину рядка як ціле значення; він ігнорує будь-які символи, які не можна інтерпретувати як частину позначення цілого числа, і не вказується, що будь-які такі символи були проігноровані.

Тут є дві важливі частини. Я посмілив їх обох. Отже, перш за все, ми повинні з'ясувати, що таке toStringпредставництво null. Нам потрібно переглянути Table 13 — ToString Conversionsв розділі 9.8.0 цю інформацію:

введіть тут опис зображення

Чудово, тому тепер ми знаємо, що робити toString(null)внутрішньо - це результат'null' рядок. Чудово, але як саме він обробляє цифри (символи), які не відповідають дійсності в заданому радіусі?

Ми переглядаємо вище 15.1.2.2та бачимо таке зауваження:

Якщо S містить будь-який символ, який не є цифрою Rx, R, то нехай Z є підрядком S, що складається з усіх символів перед першим таким символом; інакше нехай Z буде S.

Це означає, що ми обробляємо всі цифри PRIOR до заданого радіусу і ігноруємо все інше.

В основному, робити parseInt(null, 23)те саме, що і parseInt('null', 23). uВикликає два l«S ігноруються (навіть якщо вони є частиною РАДІКС 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 містить будь-який символ, який не є цифрою Rx, R, то нехай Z є підрядком S, що складається з усіх символів перед першим таким символом; інакше нехай Z буде S.

яка є частиною, яка гарантує, що цілі літерали у стилі C люблять 15Lправильно розбирати, тому вищезазначене еквівалентно

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

"n" - це 23-та літера цифрного списку вище.

QED


16

Я думаю, що nullвін перетворюється на рядок "null". Так що nнасправді 23в 'base24' (те саме в 'base25' +), uнедійсно в 'base24', тому решта рядка nullбуде ігнорована. Ось чому він виводить, 23поки uне стане дійсним у "base31".


7

parseInt використовує буквено-цифрове представлення, тоді в base-24 "n" є дійсним, але "u" недійсним символом, тоді parseInt розбирає лише значення "n" ....

parseInt("n",24) -> 23

як приклад, спробуйте з цим:

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

Результатом буде "3".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.