From what I understand, octal literals (of the form 023) are not valid in ECMAScript 5, but are widely supported. In ECMAScript 6, they are newly supported in the format 0o23 or 0O23. What confuses me is the behavior of numbers that are not valid octal numbers, but have a preceding zero (019). These seem to behave as normal, decimal numbers.
So without strict mode, I can get things like 022 === 018 (true), because 022 is interpreted as octal, and presumably 018 is treated as decimal since it can't be octal.
In strict mode, I get an error when using a valid octal number in that format (eg 022), but not when using a zero-prefixed number that can't be a valid octal number (eg 018).
This seems very odd to me, like JS (strict-mode) is telling me that I can put a 0 in front of my number, as long as it is an INVALID octal. In ES6 (or later), will zero-prefixed numbers (possible octals or otherwise) be invalid, or treated as decimals?
This is a documented feature:
Decimal literals can start with a zero (0) followed by another
decimal digit, but If all digits after the leading 0 are smaller than
8, the number is interpreted as an octal number. This won't throw in
JavaScript.
If you want to force treating a number as octal you can use new literal form 0o (or 0O) introduced in ES6.
Related
Try this:
var num = 040;
console.log(num); // 32
Since when is 40 = 32?
TL;DR
It's being treated as octal (base 8) because of the leading 0, just like a leading 0x would make it hex (base 16). This has a long and tortured history and is no longer how octal numbers are written in modern JavaScript. In modern JavaScript using strict mode, the "legacy" octal format is a syntax error; octal numbers are written with an 0o prefix.
History
Early on (in the initial language from Netscape and the first and second ECMAScript specifications), a leading 0 on a numeric literal officially meant octal (base 8), just as a leading 0x means hexadecimal (base 16):
OctalIntegerLiteral ::
0 OctalDigit
OctalIntegerLiteral OctalDigit
E.g., 10, 012, and 0xA were all ways of writing the decimal number ten. This is in keeping with some other languages with syntax similar to JavaScript (C, C++, Java, ...), but it's highly confusing.
As of ECMAScript 3, that form of octal literal was downgraded to an optional extension, and decimal integer literals were changed so that they can't have leading zeros (unless the implementation includes the extension):
DecimalIntegerLiteral ::
0
NonZeroDigit DecimalDigits(opt)
But ECMAScript 5 forbade doing that in strict-mode:
A conforming implementation, when processing strict mode code (see
10.1.1), must not extend the syntax of NumericLiteral to include OctalIntegerLiteral as described in B.1.1.
ECMAScript 6 (ECMAScript 2015) introduces BinaryIntegerLiteral and OctalIntegerLiteral, so now we have more coherent literals:
BinaryIntegerLiteral, prefixed with 0b or 0B.
OctalIntegerLiteral, prefixed with 0o or 0O.
HexIntegerLiteral, prefixed with 0x or 0X.
The old OctalIntegerLiteral extension has been renamed to LegacyOctalIntegerLiteral, which is still allowed in non-strict mode.
Conclusion
Therefore, if you want to parse a number in base 8, use the 0o or 0O prefixes (not supported by old browsers), or use parseInt.
And if you want to be sure your numbers will be parsed in base 10, remove leading zeros, or use parseInt.
Examples
010
In strict mode (requires ECMAScript 5), it's a syntax error.
In non-strict mode, it may be a syntax error or return 8 (implementation dependent).
0o10, 0O10
Before ECMAScript 6, they're syntax errors.
In ECMAScript 6, they return 8.
parseInt('010', 8)
It returns 8.
parseInt('010', 10)
It returns 10.
If you're interested, you can find the current living specification here, and historical versions here.
With a leading zero, the number is interpreted as octal and 4 * 8 = 32.
Because the 0 prefix indicates an octal number (base 8).
Why does console.log(0123); log the integer . 83? I'm not sure why it would and don't really have an idea either.
Because it's interpreted as an octal number, and octal 123 corresponds to decimal 83 (64 + 16 + 3).
From MDN:
Leading 0 (zero) on an integer literal, or leading 0o (or 0O)
indicates it is in octal. Octal integers can include only the digits
0-7.
Because the leading 0 (zero) 0o or 0O on an integer indicates an octal number!!
Octal numbering system is used less nowadays and has almost disappeared as a digital base number system. Hexadecimal numbering system is so popular now!
I'm taking a numerical input as an argument and was just trying to account for leading zeroes. But it seems javascript converts the number into octal before I can do anything to the number. The only way to work around it so far is if I pass the number as a string initially but I was hoping there'd be another way to convert it after it is passed? So far tried (using 017 which alerted me to the octal behaviour):
017.toString(10) // 15
parseInt(017,10) // 15
017 + "" //15
new Number(017) //15
new Number('017') //17
parseInt('017', 10) // 17
So given
function(numb) {
if (typeof numb === number) {
// remove leading zeroes and convert to decimal
}
else {
// use parseInt
}
}
'use strict' also doesn't seem to solve this as some older posts have suggested. Any ideas?
If you take "numerical input", you should always definitely guaranteed have a string. There's no input method in this context that I know that returns a Number. Since you receive a string, parseInt(.., 10) will always be sufficient. 017 is only interpreted as octal if written literally as such in source code (or when missing the radix parameter to parseInt).
If for whatever bizarre reason you do end up with a decimal interpreted as octal and you want to reverse-convert the value back to a decimal, it's pretty simple: express the value in octal and re-interpret that as decimal:
var oct = 017; // 15
parseInt(oct.toString(8), 10) // 17
Though because you probably won't know whether the input was or wasn't interpreted as octal originally, this isn't something you should have to do ever.
JavaScript interprets all numbers beginning with a 0, and containing all octal numerals as octals - eg 017 would be an octal but 019 wouldn't be. If you want your number as a decimal then either
1. Omit the leading 0.
2. Carry on using parseInt().
The reason being is that JavaScript uses a few implicit conversions and it picks the most likely case based on the number. It was decided in JavaScript that a leading 0 was the signal that a number is an octal. If you need that leading 0 then you have to accept that rule and use parseInt().
Source
If you type numbers by hand to script then not use leading zeros (which implicity treat number as octal if it is valid octal - if not then treat it as decimal). If you have number as string then just use + operator to cast to (decimal) number.
console.log(+"017")
if (021 < 019) console.log('Paradox');
The strict mode will not allow to use zero prefix
'use strict'
if (021 < 019) console.log('Paradox');
This question already has answers here:
How to parseInt a string with leading 0
(6 answers)
Closed 8 years ago.
avar = "0000013482000000";
t = parseInt(avar);
When I run that, t is 92 for some reason. If I remove the leading 0's, then it works just fine. Why would that be?
Try this:
avar = "0000013482000000";
t = parseInt(avar,10);
Some browsers might assume that it is an octal number if the string starts with 0.
However, ,10 is not required in modern browsers with new ECMAScript standards because they will always be considered as decimal unless specified or starts with 0x (hexadecimal).
Chrome is one of those browsers that has a default radix of 10.
Reference: ECMAScript Language Specification Page 104
The parseInt function produces an integer value dictated by interpretation of the contents of the string
argument according to the specified radix. Leading white space in string is ignored. If radix is undefined or 0,
it is assumed to be 10 except when the number begins with the character pairs 0x or 0X, in which case a radix
of 16 is assumed. If radix is 16, the number may also optionally begin with the character pairs 0x or 0X.
Use the second parameter (radix):
t = parseInt(avar, 10);
To specify that the number should be parsed in base 10.
From the MDN docs:
If radix is undefined or 0 (or absent), JavaScript assumes the following:
If the input string begins with "0x" or "0X", radix is 16 (hexadecimal) and the remainder of the string is parsed.
If the input string begins with "0", radix is eight (octal) or 10 (decimal). Exactly which radix is chosen is implementation-dependent. ECMAScript 5 specifies that 10 (decimal) is used, but not all browsers support this yet. For this reason always specify a radix when using parseInt.
If the input string begins with any other value, the radix is 10 (decimal).
And in reference to ECMAScript 5:
The parseInt function produces an integer value dictated by interpretation of the contents of the string argument according to the specified radix. Leading white space in string is ignored. If radix is undefined or 0, it is assumed to be 10 except when the number begins with the character pairs 0x or 0X, in which case a radix of 16 is assumed. If radix is 16, number may also optionally begin with the character pairs 0x or 0X.
Reference:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt
Parsing a number with leading zeros causes the number to be treated as octal. To override this you need to set the radix parameter of parseInt to 10 (base 10 as opposed to base 8).
parseInt assumes octal notation if you have a leading zero, so you want to pass in a radix as the second parameter, telling the function to parse the string as a base 10 int.
parseInt(avar, 10)
should fix it.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Workarounds for JavaScript parseInt octal bug
I would think it has something to do with octal parsing, since it only happens on 8 or 9. There was also the thought that this was a Chrome bug, but it replicates in Firefox as well.
Is this intentional behavior? If so, why?
The solution here is simple. NEVER call parseInt() without specifying the desired radix. When you don't pass that second parameter, parseInt() tries to guess what the radix is based on the format of the number. When it guesses, it often gets it wrong.
Specify the radix like this and you will get the desired result:
parseInt("08", 10) == 8;
As to what rules it uses for guessing, you can refer to the MDN doc page for parseInt().
If radix is undefined or 0, JavaScript assumes the following:
If the input string begins with "0x" or "0X", radix is 16
(hexadecimal).
If the input string begins with "0", radix is eight
(octal). This feature is non-standard, and some implementations
deliberately do not support it (instead using the radix 10). For this
reason always specify a radix when using parseInt.
If the input string
begins with any other value, the radix is 10 (decimal). If the first
character cannot be converted to a number, parseInt returns NaN.
So, according to these rules, parseInt() will guess that "08" is octal, but then it encounters a digit that isn't allowed in octal so it returns 0.
When you pass a number to parseInt(), it has nothing to do because the value is already a number so it doesn't try to change it.
"Is this intentional behavior?"
Yes.
"If so, why?"
A leading 0 is the notation used for denoting an octal number as defined in the specification. The symbols 8 and 9 don't exist in octal numbering, so parseInt uses the first valid number it finds, which is 0.
If you do...
parseInt('123#xq$_.f(--_!2*')
...the result will be...
123
...because a valid number was found at the beginning of the string. Anything invalid beyond that is discarded.
You can fix this like that :
parseInt("080".replace(/^[0]+/g,""));