Почему восьмеричный литерал в виде строки, приведенной к числу? - PullRequest
23 голосов
/ 30 марта 2010

В JavaScript почему восьмеричное число преобразуется в десятичное число? Я могу привести шестнадцатеричную буквенную строку, используя Number() или +, почему не восьмеричное?

Например:

1000 === +"1000" // -> true
0xFF === +"0xFF" // -> true
0100 === +"0100" // -> false - +"0100" gives 100, not 64

Я знаю, что могу разобрать с parseInt("0100" [, 8]), но мне хотелось бы знать, почему приведение не работает так же, как с шестнадцатеричными и декарными числами

Кроме того, кто-нибудь знает, почему восьмеричные литералы отбрасываются из ECMAScript 5th Edition в строгом режиме?

Ответы [ 3 ]

24 голосов
/ 04 октября 2010

Я немного опоздал на вопрос, но думаю, что могу дать хороший ответ.

Принятый ответ не говорит вам ничего более того, что вы на самом деле знаете, и упоминает в самом вопросе: Number(value) работает как +value, но не как parseInt(value).

Ключ должен знать, что есть семантическая разница между преобразованием типа и синтаксическим анализом .

Почему восьмеричное число преобразуется в десятичное число?

Поскольку конструктор Number вызывается как функция (Number(value)) и Unary + Operator (+value) за сценой, используется ToNumber внутренняя операция. Целью этих конструкций является преобразование типов .

Когда ToNumber применяется к строковому типу , используется специальное грамматическое произведение, называемое StringNumericLiteral.

Эта продукция может содержать только литералы Decimal и Hexadecimal Integer:

...

StrNumericLiteral :::
   StrDecimalLiteral
   HexIntegerLiteral

...

Есть также семантические различия между этой грамматикой и грамматикой "нормального" NumericLiterals.

A StringNumericLiteral:

  • Может предшествовать и / или следовать за пробелами и / или символами конца строки.
  • Это десятичное число может иметь любое количество первых 0 цифр. без восьмеричных чисел!
  • Десятичному символу может предшествовать + или - для обозначения его знака.
  • То, что пусто или содержит только пробел, преобразуется в + 0.

Теперь я пойду с функциями parseInt и parseFloat.

Очевидно, что целью этих функций является синтаксический анализ , который семантически отличается от преобразования типа , например:

parseInt("20px");     // 20
parseInt("10100", 2); // 20
parseFloat("3.5GB");  // 3.5
// etc..

Стоит отметить, что алгоритм parseInt изменен в спецификации ECMAScript 5-го издания, он больше не интерпретирует основание числа как восьмеричное только для начального нуля:

parseInt("010"); // 10, ECMAScript 5 behavior
parseInt("010"); // 8,  ECMAScript 3 behavior

Как вы можете видеть, это внесло несовместимость в поведение между реализациями ES3 и ES5, и, как всегда, рекомендуется использовать аргумент radix, чтобы избежать любых возможных проблем.

Теперь ваш второй вопрос:

Почему восьмеричные литералы удаляются из ECMAScript 5th Edition в строгом режиме?

На самом деле, эта попытка избавиться от восьмеричных литералов происходит с 1999 года. Восьмеричные производные литералов (OctalIntegerLiteral и OctalEscapeSequence) были удалены из грамматики NumericLiteral с начиная со спецификации ECMAScript 3rd Edition , они могут быть включены для обратной совместимости ( также в ES5 ) с более старыми версиями стандарта.

Фактически, они включены во все основные реализации, но технически совместимая с ES3 или ES5 реализация может предпочесть не включать их, потому что они описаны как ненормативный .

Это был первый шаг, теперь ECMAScript 5 Строгий режим полностью их запрещает.

Но почему?

Поскольку они считались подверженными ошибкам функциями, и фактически в прошлом они вызывали непреднамеренных или трудных для обнаружения ошибок - так же, как та же проблема неявных восьмеричных чисел parseInt -.

Теперь в строгом режиме восьмеричный литерал вызовет исключение SyntaxError - в настоящее время наблюдается только в бета-версиях Firefox 4.0 -.

4 голосов
/ 30 марта 2010

Потому что вы на самом деле не выполняете приведение в правильном смысле (JS не использует приведение) - это просто жонглирование типа.

Когда у вас есть какой-либо литерал в Javascript и вы используете метод для него, объект создается за кулисами для вас.

"foo".toUpperCase(), например, заменяется оценкой кода, который будет выглядеть примерно так new String( "foo" ).toUpperCase();

Поскольку строки не могут быть оценены с помощью унарного оператора +, JS преобразует вашу строку в число - и он не использует parseInt() или parseFloat() для внутреннего использования - как вы уже догадались - он использует Number().

Итак, значение, которое вы видите, - это то, что вы увидите по возвращению Number () , которое, по-видимому, не принимает восьмеричные числа.

2 голосов
/ 04 октября 2010

Чтобы понять, почему восьмеричная поддержка была удалена в ES5, это в основном потому, что для новичка или не программиста синтаксис является неожиданным. Представьте, что выровнены по вертикали ряды чисел (возможно, добавляются), например, для их выравнивания используются начальные нули - если ваши числа не используют 8 или 9, они будут рассматриваться как восьмеричные. Внезапно ваш код исчезает без видимой причины! Вот почему восьмеричная поддержка была удалена. Когда-нибудь может быть добавлен другой восьмеричный синтаксис, если он не создаст такой неудачи (я думаю, я помню, что 0o755 вижу как идею одного соломника), но пока восьмеричный отсутствует.

Относительно несовместимого parseInt изменения, отмеченного в предыдущих ответах: ни одна реализация не внесла это изменение, и я подозреваю, что никакая реализация не сделает это. ES5 в основном основан на реальности. Его новые функции обычно не нарушают существующий код (за исключением того, что новый код, конечно, должен позаботиться об использовании новых функций, чтобы не нарушать существующий код как часть этого использования), который не пытается использовать новые функции. Его несовместимость также в основном незначительна, или они неактуальны, потому что реальные реализации беспечно игнорировали спецификацию из соображений совместимости. Но не все несовместимости обоснованы: некоторые из них являются скорее желательными, чем гармонизирующими. Изменение на parseInt является примером желательного изменения. Он нарушает существующий код, который ожидает, что восьмеричный синтаксис без явного осциллятора будет анализироваться как восьмеричный.

В течение нескольких дней SpiderMonkey (движок JavaScript Mozilla) реализовал половинное изменение, чтобы сделать parseInt при вызове из кода строгого режима, игнорировать восьмеричное и поддерживать восьмеричное, когда не вызывается из кода строгого режима. Это ближе к тому, что хочет ES5, но это явное препятствие для преобразования нестрогого кода в строгий режим, это, вероятно, будет сбивать с толку пользователя, и - возможно, наиболее интересно для разработчиков - это означает, что вы не сможете реализовать parseInt в самом JavaScript (потому что в спецификации нет способа проверить строгость вызывающей функции), что может быть желательно в будущем (для уменьшения поверхности атаки, упрощения реализации и т. Д.). Таким образом, мы сняли зависимость. (Я написал патч, чтобы сделать parseInt зависимым от вызывающего абонента, и я рассмотрел патч, чтобы отменить его, порожденный дальнейшим обсуждением после того, как мой первоначальный патч приземлился.) parseInt теперь снова соответствует ES3, и с учетом веб как есть и что семантика ES5, вероятно, не совместима с ним, я сомневаюсь, что мы изменим. Поэтому я сомневаюсь, что другие тоже изменятся. (Я также почти уверен, что они согласятся с нашей оценкой степени несовместимости Интернета с желательным запретом ES5 неявного восьмеричного синтаксиса в parseInt, и, вероятно, с другими нашими причинами. Даже если бы мы изменили I Я не уверен, что они будут следовать, и я подозреваю, что они были бы умны, чтобы не.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...