Почему не восьмеричный литерал как строка, отлитая от числа?
В JavaScript, почему восьмеричная строка чисел представлена как десятичное число? Я могу использовать строчную строку с использованием Number()
или +
, почему не восьмеричный?
Например:
1000 === +"1000" // -> true
0xFF === +"0xFF" // -> true
0100 === +"0100" // -> false - +"0100" gives 100, not 64
Я знаю, что могу разбираться с parseInt("0100" [, 8])
, но я хотел бы знать, почему кастинг не работает, как с шестнадцатеричными и десятичными числами.
Кроме того, кто-нибудь знает, почему восьмеричные литеры отбрасываются из ECMAScript 5th Edition в строгом режиме?
Ответы
Ответ 1
Я немного опаздываю на этот вопрос, но думаю, что могу дать хороший ответ.
Принятый ответ не говорит вам ничего более того, что вы на самом деле знаете, и упоминаете в самом вопросе: Number(value)
работает как +value
, но не как parseInt(value)
.
Ключ должен знать, что существует семантическая разница между преобразованием типов и синтаксическим разбором.
Почему строка восьмеричного числа приводится в виде десятичного числа?
Потому что конструктор чисел называется функцией (Number(value)
) и Унарный +
Оператор (+value
) за кулисами использует внутреннюю операцию ToNumber
. Целью этих конструкций является преобразование типа .
Когда ToNumber
применяется к типу String, используется специальная грамматическая постановка, называемая StringNumericLiteral
.
Это произведение может содержать только десятичные литералы и шестнадцатеричные целые литеры:
...
StrNumericLiteral :::
StrDecimalLiteral
HexIntegerLiteral
...
Существуют также семантические различия между этой грамматикой и грамматикой "нормального" NumericLiterals
.
A StringNumericLiteral
:
- Может предшествовать и/или сопровождать пробелы и/или терминаторы строк.
- Это десятичное число может иметь любое число ведущих 0 цифр. no восьмеричные!
- Это десятичное значение может предшествовать + или - для указания его знака.
- Это пустое или содержит только пробел, преобразуется в +0.
Теперь я перейду к функциям parseInt
и parseFloat
.
Цель этих функций, очевидно, состоит в сильном анализе , который семантически отличается от преобразования типа, например:
parseInt("20px"); // 20
parseInt("10100", 2); // 20
parseFloat("3.5GB"); // 3.5
// etc..
Стоит упомянуть, что алгоритм parseInt
изменен в спецификации ECMAScript 5th Edition, он больше не интерпретирует числовое значение как восьмеричное для наличия начального нуля:
parseInt("010"); // 10, ECMAScript 5 behavior
parseInt("010"); // 8, ECMAScript 3 behavior
Как вы можете видеть, это ввело несовместимость в поведение между реализациями ES3 и ES5 и, как всегда, рекомендуется использовать аргумент radix, чтобы избежать возможных проблем.
Теперь ваш второй вопрос:
Почему восьмеричные литералы исключаются из ECMAScript 5th Edition в строгом режиме?
На самом деле, это стремление избавиться от восьмеричных литералов происходит с 1999 года. Из грамматики NumericLiteral
были удалены восьмеричные литературные произведения (OctalIntegerLiteral
и OctalEscapeSequence
), так как спецификация ECMAScript 3rd Edition, они могут быть включены для обратная совместимость (также в ES5) со старыми версиями стандарта.
Фактически, они включены во все основные реализации, но технически реализация, совместимая с ES3 или ES5, может не включать их, поскольку они описываются как ненормативный.
Это был первый шаг, теперь ECMAScript 5 Strict Mode полностью запрещает их.
Но почему?
Потому что они считались функцией, подверженной ошибкам, и на самом деле в прошлом они приводили к непреднамеренным или трудно улавливаемым ошибкам - так же, как та же проблема неявных восьмерик parseInt
-.
Теперь, в строгом режиме, восьмеричный литерал вызовет исключение SyntaxError
- в настоящее время доступно только в Firefox 4.0 Betas -.
Ответ 2
Потому что вы на самом деле не выполняете кастинг в правильном смысле (у JS нет кастинга) - он просто набирает жонглирование.
Когда у вас есть какой-либо литерал в Javascript и вводится метод, он создается за кулисами.
"foo".toUpperCase()
, например, заменяется оценкой кода, который будет примерно похож на этот new String( "foo" ).toUpperCase();
Поскольку строки не могут быть оценены с помощью унарного оператора +
, JS преобразует вашу строку в число - и она не использует parseInt()
или parseFloat()
внутренне - вы догадались - она использует Number()
.
Итак, значение, которое вы видите, - это то, что вы увидите из возврата Number(), который не отображается предположим восьмеричные.
Ответ 3
Чтобы выяснить, почему восьмая поддержка была удалена в ES5, это главным образом потому, что для новичков или не-программистов синтаксис является неожиданным. Представьте себе вертикальное выравнивание ряда чисел (возможно, добавление), используя ведущие нули для их выравнивания, например - если ваши номера не используют 8 или 9, они будут обрабатываться как восьмеричные. Внезапно ваш код исчез в сорняках без какой-либо очевидной причины! Вот почему восьмеричная поддержка была удалена. Другой восьмеричный синтаксис может когда-нибудь быть добавлен, если он не создает такого несчастья (я думаю, что я помню, что я видел 0o755
как одну идею соломона), но на данный момент восьмеричный отсутствует.
Относительно несовместимого изменения parseInt
, отмеченного в прошлых ответах: никакая реализация не сделала это изменение, и я подозреваю, что никакая реализация не сделает этого. ES5 в основном основан на реальности. Его новые функции обычно не нарушают существующий код (за исключением того, что новый код, конечно, должен заботиться о том, чтобы использовать новые функции, чтобы не нарушать существующий код как часть этого использования), который не пытается использовать новые функции. Его несовместимости в основном незначительны, или они неактуальны, поскольку реалии в реальном мире небрежно игнорируют спецификацию по причинам совместимости. Но не все несовместимости являются обоснованными: некоторые из них более желательны, чем гармонизация. Изменение к parseInt
является примером желательного изменения. Он разбивает существующий код, который ожидает восьмеричного синтаксиса, без явного основания, для синтаксического анализа как восьмеричного.
В течение нескольких дней SpiderMonkey (движок Mozilla JavaScript) реализовал половинное изменение, чтобы сделать parseInt
, когда вызывается из строкового кода режима, игнорирует восьмеричную и поддерживает восьмеричную, когда не вызывается из строкового кода режима. Это ближе к тому, что хочет ES5, но это явное препятствие для преобразования нестрого кода в строгий режим, вероятно, это смущает пользователя и, возможно, самое интересное для разработчиков, значит, вы не смогли реализовать parseInt
в самом JavaScript (потому что в спецификации нет способа проверить строгость одной вызывающей функции), что может быть желательно в будущем (уменьшить поверхность атаки, облегчить реализацию и т.д.). Таким образом, мы сократили зависимость. (Я написал патч, чтобы сделать parseInt
зависимым от вызывающего, и я просмотрел патч, чтобы его отменить, порожденный дальнейшим обсуждением после того, как мой начальный патч приземлился.) parseInt
теперь соответствует ES3 снова, и данный веб-интерфейс, и что семантика ES5, вероятно, не совместима с ней, я сомневаюсь, что мы изменимся. Поэтому я сомневаюсь, что и другие изменятся. (Я также уверен, что они согласятся с нашей оценкой степени несовместимости Интернета с ES5, стремящейся запретить неявный восьмеричный синтаксис в parseInt
, и, вероятно, с нашими другими причинами. Даже если бы мы изменили я "Я не уверен, что они последуют, и я подозреваю, что они были бы умны, чтобы не делать этого.)