为什么八进制文字不作为字符串转换为数字?

发布于 2024-08-27 11:48:11 字数 410 浏览 9 评论 0 原文

在 JavaScript 中,为什么八进制数字字符串会转换为十进制数字?我可以使用 Number()+ 转换十六进制文字字符串,为什么不转换八进制呢?

例如:

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

我知道我可以使用 parseInt("0100" [, 8]) 进行解析,但我想知道为什么转换不能像处理十六进制和十进制数字那样工作。

另外,有谁知道为什么八进制文字在严格模式下从 ECMAScript 第五版中删除?

In JavaScript, why does an octal number string cast as a decimal number? I can cast a hex literal string using Number() or +, why not an octal?

For instance:

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

I know I can parse with parseInt("0100" [, 8]), but I'd like to know why casting doesn't work like it does with hex and dec numbers.

Also, does anyone know why octal literals are dropped from ECMAScript 5th Edition in strict mode?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

并安 2024-09-03 11:48:11

我的问题有点晚了,但我想我可以给出一个很好的答案。

接受的答案不会告诉您更多您实际知道的内容,并在问题本身中提到: Number(value) 用作 +value 但不用作 parseInt(值)

关键是要知道类型转换解析之间存在语义差异

为什么八进制数字字符串会转换为十进制数字?

因为 作为函数调用的 Number 构造函数 (Number(value)< /code>) 和 一元 + 运算符 ( +value) 在幕后使用 ToNumber内部操作。这些构造的目的是类型转换

ToNumber 应用于字符串类型时,一个特殊的使用称为StringNumericLiteral的语法产生式。

此产生式只能保存十进制文字和十六进制整数文字:

...

StrNumericLiteral :::
   StrDecimalLiteral
   HexIntegerLiteral

...

此语法与“正常”语法 数字文字

A StringNumericLiteral:

  • 前面和/或后面可以有空格和/或行终止符。
  • 即小数可以有任意数量的前导 0 数字。 没有八进制!
  • 即十进制前面可以加 + 或 − 来指示其符号。
  • 即为空或仅包含空格时将转换为+0。

现在我将使用 parseIntparseFloat 函数。

这些函数的目的显然是解析,这在语义上与类型转换不同,例如:

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

值得一提的是parseInt 在 ECMAScript 第五版规范中进行了更改,它不再仅仅因为有一个前导零就将数字的基数解释为八进制:

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

如您所见,这引入了 ES3 和 ES5 实现之间的行为不兼容,并且一如既往地建议使用基数参数,以避免任何可能的问题。

现在你的第二个问题:

为什么八进制文字在严格模式下从 ECMAScript 第五版中被删除?

实际上,这种摆脱八进制文字的努力始于 1999 年。八进制文字产生式(OctalIntegerLiteralOctalEscapeSequence)已从 NumericLiteral 语法中删除> 自 ECMAScript 第三版规范以来,它们可能被包含在内向后兼容性 (也在 ES5 中)以及旧版本的标准。

事实上,它们包含在所有主要实现中,但从技术上讲,符合 ES3 或 ES5 的实现可以选择不包含它们,因为它们被描述为非规范

这是第一步,现在 ECMAScript 5 严格模式 完全不允许它们。

但为什么?

因为它们被认为是容易出错的功能,事实上,在过去它们会导致无意难以捕获错误 - 就像与 parseInt 的隐式八进制相同的问题 —。

现在,在严格模式下,八进制文字将导致 SyntaxError 异常 - 目前仅在 Firefox 4.0 Betas 中观察到 -。

I'm a bit late to the question but I think I can give a good answer.

The accepted answer doesn't tell you anything more that what you actually know, and mention in the question itself: Number(value) works as +value but not as parseInt(value).

The key is to know that there is a semantic difference between type conversion and parsing.

Why does an octal number string cast as a decimal number?

Because the Number constructor called as a Function (Number(value)) and the Unary + Operator (+value) behind the scenes use the ToNumber internal operation. The purpose of those constructs is type conversion.

When ToNumber is applied to the String Type a special grammar production is used, called the StringNumericLiteral.

This production can hold only Decimal literals and Hexadecimal Integer literals:

...

StrNumericLiteral :::
   StrDecimalLiteral
   HexIntegerLiteral

...

There are also semantic differences between this grammar and the grammar of "normal" NumericLiterals.

A StringNumericLiteral:

  • May be preceded and/or followed by white space and/or line terminators.
  • That is decimal may have any number of leading 0 digits. no octals!
  • That is decimal may be preceded by + or − to indicate its sign.
  • That is empty or contains only white space is converted to +0.

Now I will go with the parseInt and parseFloat functions.

The purpose of those functions obviously is parsing, which is semantically different to type conversion, for example:

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

Is worth mentioning that the algorithm of parseInt changed in the ECMAScript 5th Edition Specification, it no longer interprets a number's radix as octal just for having a leading zero:

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

As you can see, that introduced an incompatibility in the behavior between ES3 and ES5 implementations, and as always is recommended to use the radix argument, to avoid any possible problems.

Now your second question:

Why octal literals are dropped from ECMAScript 5th Edition in strict mode?

Actually, this effort of getting rid of octal literals comes since 1999. The octal literal productions (OctalIntegerLiteral and OctalEscapeSequence) were removed from the grammar of NumericLiterals since the ECMAScript 3rd Edition specification, they might be included for backwards compatibility (also in ES5) with older versions of the standard.

In fact, they are included in all major implementations, but technically an ES3 or ES5 compliant implementation could choose to not include them, because they are described as non-normative.

That was the first step, now ECMAScript 5 Strict Mode disallows them completely.

But why?

Because they were considered to be an error prone feature, and in fact, in the past they caused unintentional or hard to catch bugs — just as the same problem of implicit octals of parseInt —.

Now, under strict mode an octal literal will cause a SyntaxError exception — currently only observable in Firefox 4.0 Betas —.

您的好友蓝忘机已上羡 2024-09-03 11:48:11

因为你实际上并没有执行正确意义上的转换(JS 没有转换)——这只是类型杂耍。

当您在 Javascript 中拥有任何文字并对其执行方法时,就会在幕后为您创建一个对象。

例如,"foo".toUpperCase() 被替换为大致如下所示的代码评估 new String( "foo" ).toUpperCase();

字符串不能使用一元 + 运算符进行计算,JS 将字符串转换为数字 - 并且它不使用 parseInt()parseFloat() 内部 - 你猜对了 - 它使用 Number()

因此,您看到的值就是您从 Number 返回值中看到的值(),它似乎不采用八进制。

Because you're not actually performing casting in the proper sense (JS doesn't have casting) - it's just type juggling.

When you have any literal in Javascript and enact a method on it, an object is created behind the scenes for you.

"foo".toUpperCase() for example, is replaced by the evaluation of code that would roughly look like this new String( "foo" ).toUpperCase();

Since strings can't be evaluated with a unary + operator, JS converts your string to a number - and it doesn't use parseInt() or parseFloat() internally - you guessed it - it uses Number().

So, the value you see is the what you'd see from the return of Number(), which doesn't appear to assume octals.

半仙 2024-09-03 11:48:11

详细说明为什么 ES5 中删除了八进制支持,主要是因为对于新手或非程序员来说,语法是意想不到的。想象一下垂直对齐一系列数字(可能是相加的),例如使用前导零来对齐它们——如果您的数字不使用 8 或 9,它们最终将被视为八进制。突然间,您的代码无缘无故地消失了!这就是删除八进制支持的原因。如果不会造成这样的不幸的话,有一天可能会添加不同的八进制语法(我想我记得看到 0o755 作为一个稻草人的想法),但现在八进制已经过时了。

关于过去回复中提到的不兼容的 parseInt 更改:没有实现进行此更改,并且我怀疑没有实现会做出此更改。 ES5 大部分是基于现实的。它的新功能通常不会破坏不尝试使用新功能的现有代码(当然,新代码在使用新功能时必须注意不要破坏现有代码作为该使用的一部分)。它的不兼容性也大多可以忽略不计,或者它们是无关紧要的,因为现实世界的实现出于兼容性原因而轻率地忽略了规范。但并非所有的不兼容都是有充分根据的:有些不兼容更多的是出于愿望而不是协调。对 parseInt 的更改是一个理想更改的示例。它打破了现有的代码,需要八进制语法,没有显式基数,解析为八进制。

在几天的时间里,SpiderMonkey(Mozilla 的 JavaScript 引擎)实现了一个中途更改,使 parseInt 在从严格模式代码调用时忽略八进制,并在不从严格模式代码调用时支持八进制。这更接近 ES5 想要的,但它显然是把非严格代码转换为严格模式的障碍,它可能会让用户感到困惑,而且——也许对实现者来说最有趣的是——这意味着你无法实现 < JavaScript 本身中的 code>parseInt (因为规范中没有办法检查调用函数的严格性),这在将来的某个时候可能是需要的(以减少攻击面、简化实现等)。所以我们取消了依赖。 (我编写了补丁来使 parseInt 依赖于调用者,并且我审查了该补丁以撤消它,这是在我的初始补丁落地后通过进一步讨论产生的。) parseInt 现在符合又是 ES3,考虑到 Web 的现状,并且 ES5 的语义可能与其不兼容,我怀疑我们会做出改变。因此我怀疑其他人也会改变。 (我也很确定他们会同意我们对 ES5 在 parseInt 中禁止隐式八进制语法的网络不兼容程度的估计,并且可能也同意我们的其他原因。即使我们要改变,我不确定他们会跟随,但我怀疑他们不这样做是明智的。)

To elaborate on why octal support was removed in ES5, it's mostly because, to the novice or non-programmer, the syntax is unexpected. Imagine vertically aligning a series of numbers (perhaps being added), using leading zeroes to align them, for example -- if your numbers don't use 8 or 9, they'll end up being treated as octal. Suddenly your code's off in the weeds for no obvious reason! This is why octal support was removed. A different octal syntax might someday be added if it doesn't create such a misfortune (I think I remember seeing 0o755 as one strawman idea), but for now octal is out.

Regarding the incompatible parseInt change noted in past responses: no implementation has made this change, and I suspect no implementation will make it. ES5 is mostly grounded in reality. Its new features generally don't break existing code (except that new code of course must take care in using new features not to break existing code as part of that use) that doesn't try to use the new features. Its incompatibilities are mostly negligible as well, or they're irrelevant because real-world implementations blithely ignored the specification for compatibility reasons. But not all the incompatibilities are well-founded: some are more aspirational than harmonizing. The change to parseInt is an example of an aspirational change. It breaks existing code that expects octal syntax, without an explicit radix, to parse as octal.

For the span of a few days SpiderMonkey (Mozilla's JavaScript engine) implemented a halfway-change to make parseInt, when called from strict mode code, disregard octal, and to support octal when not called from strict mode code. This is closer to what ES5 wants, but it's a clear impediment to converting non-strict code to strict mode, it would likely be confusing to the user, and -- perhaps most interestingly for implementers -- it means you couldn't implement parseInt in JavaScript itself (because there's no way in the specification to examine the strictness of one's calling function), as might be desirable at some future time (to reduce attack surface, ease implementation, and so on). So we undid the dependency. (I wrote the patch to make parseInt caller-dependent, and I reviewed the patch to undo it, spawned by further discussion after my initial patch landed.) parseInt now conforms to ES3 again, and given the web as it is, and that ES5's semantics are probably not compatible with it, I doubt we'll change. Therefore I doubt others will change, either. (I'm also pretty sure they'd agree with our estimation of the degree of incompatibility of the web with ES5's aspirational forbidding of implicit octal syntax in parseInt, and probably with our other reasons too. Even if we were to change I'm not sure they would follow, and I suspect they'd be smart not to.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文