为什么八进制文字不作为字符串转换为数字?
在 JavaScript 中,为什么八进制数字字符串会转换为十进制数字?我可以使用 Number()
或 +
转换十六进制文字字符串,为什么不转换八进制呢?
例如:
1000 === +"1000" // -> true
0xFF === +"0xFF" // -> true
0100 === +"0100" // -> false - +"0100" gives 100, not 64
我知道我可以使用 parseInt("0100" [, 8])
进行解析,但我想知道为什么转换不能像处理十六进制和十进制数字那样工作。
另外,有谁知道为什么八进制文字在严格模式下从 ECMAScript 第五版中删除?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我的问题有点晚了,但我想我可以给出一个很好的答案。
接受的答案不会告诉您更多您实际知道的内容,并在问题本身中提到:
Number(value)
用作+value
但不用作parseInt(值)
。关键是要知道类型转换和解析之间存在语义差异。
因为 作为函数调用的 Number 构造函数 (
Number(value)< /code>) 和 一元
+
运算符 (+value
) 在幕后使用ToNumber
内部操作。这些构造的目的是类型转换。
当
ToNumber
应用于字符串类型时,一个特殊的使用称为StringNumericLiteral
的语法产生式。此产生式只能保存十进制文字和十六进制整数文字:
此语法与“正常”语法
数字文字
。A StringNumericLiteral:
现在我将使用
parseInt
和parseFloat
函数。这些函数的目的显然是解析,这在语义上与类型转换不同,例如:
值得一提的是
parseInt
在 ECMAScript 第五版规范中进行了更改,它不再仅仅因为有一个前导零就将数字的基数解释为八进制:如您所见,这引入了 ES3 和 ES5 实现之间的行为不兼容,并且一如既往地建议使用基数参数,以避免任何可能的问题。
现在你的第二个问题:
实际上,这种摆脱八进制文字的努力始于 1999 年。八进制文字产生式(
OctalIntegerLiteral
和OctalEscapeSequence
)已从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 asparseInt(value)
.The key is to know that there is a semantic difference between type conversion and parsing.
Because the Number constructor called as a Function (
Number(value)
) and the Unary+
Operator (+value
) behind the scenes use theToNumber
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 theStringNumericLiteral
.This production can hold only Decimal literals and Hexadecimal Integer literals:
There are also semantic differences between this grammar and the grammar of "normal"
NumericLiterals
.A
StringNumericLiteral
:Now I will go with the
parseInt
andparseFloat
functions.The purpose of those functions obviously is parsing, which is semantically different to type conversion, for example:
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: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:
Actually, this effort of getting rid of octal literals comes since 1999. The octal literal productions (
OctalIntegerLiteral
andOctalEscapeSequence
) were removed from the grammar ofNumericLiteral
s 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 —.因为你实际上并没有执行正确意义上的转换(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 thisnew String( "foo" ).toUpperCase();
Since strings can't be evaluated with a unary
+
operator, JS converts your string to a number - and it doesn't useparseInt()
orparseFloat()
internally - you guessed it - it usesNumber()
.So, the value you see is the what you'd see from the return of Number(), which doesn't appear to assume octals.
详细说明为什么 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 toparseInt
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 implementparseInt
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 makeparseInt
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 inparseInt
, 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.)