我如何解决JavaScript的parseInt八进制行为?
尝试在JavaScript中执行以下操作:
parseInt('01'); //equals 1 parseInt('02'); //equals 2 parseInt('03'); //equals 3 parseInt('04'); //equals 4 parseInt('05'); //equals 5 parseInt('06'); //equals 6 parseInt('07'); //equals 7 parseInt('08'); //equals 0 !! parseInt('09'); //equals 0 !!
我刚刚学会了JavaScript认为前导零表示一个八进制整数的困难方法,并且由于基数8中没有"8"
或"9"
,函数返回零。 喜欢与否, 这是devise 。
什么是解决方法?
注意:为了完整性,我即将发布一个解决scheme,但这是一个我讨厌的解决scheme,所以请发布其他/更好的答案。
更新:
JavaScript标准( ECMA-262 )的第5版引入了一个突破性的改变,消除了这种行为。 Mozilla有很好的写法 。
这是一个简单的解决scheme常见的Javascript陷阱:
只需指定基地或“基数”,如下所示:
parseInt('08',10); // 8
你也可以使用Number :
Number('08'); // 8
首先,在大多数情况下,你确实不需要parseInt()
。 它的algorithm充满了各种各样的怪癖, 规范中甚至禁止使用0
前缀(“函数parseInt的规范不再允许实现将string以0字符开头的string视为八进制值”),但是这需要一段时间改变浏览器行为 (即使我确信没有人在parseInt()
有意使用八进制)。 并且Internet Explorer 6将永远不会改变(然而,Internet Explorer 9却不再支持parseInt()
八进制)。 它使用的algorithm通常比你想要的要多。 在某些情况下,这是个坏主意。
- 如果第一个参数还没有被转换成string。
- 修剪数字,所以
' 4'
变成'4'
。 - 检查string是否以
-
或+
开头,并删除此字符。 如果是-
使输出为负。 - 将基数转换为整数。
- 如果基数是
0
或NaN
尝试猜测基数。 这意味着寻找(不区分大小写)0x
和(非标准)0
。 如果找不到前缀,则使用10
(这是最有可能的)。 - 如果基数如果存在,则从头开始是
16
带0x
。 - find不在基数范围内的第一个字符。
- 如果在不在基数范围内的第一个字符之前什么也没有,请返回
NaN
。 -
将数字转换为小数点,直到不在范围内的第一个字符。
例如,
parseInt('012z', 27)
给出0 * Math.pow(27, 2) + 1 * Math.pow(27, 1) + 2 * Math.pow(27, 0)
parseInt('012z', 27)
0 * Math.pow(27, 2) + 1 * Math.pow(27, 1) + 2 * Math.pow(27, 0)
parseInt('012z', 27)
0 * Math.pow(27, 2) + 1 * Math.pow(27, 1) + 2 * Math.pow(27, 0)
。
该algorithm本身并不是很快,但性能各不相同(优化造成的奇迹)。 我已经对JSPerf进行了testing,结果很有趣。 +
和~~
是最快的,除了Chrome,其中parseFloat()
以某种方式快于其他选项(比其他选项快2到5倍,其中+
实际上慢5倍)。 在Firefox中, ~~
testing非常快 – 在某些情况下,我有Infinity
循环。
另一件事是正确的。 parseInt()
, ~~
和parseFloat()
使错误无声。 如果parseInt()
和parseFloat()
字符在无效字符后被忽略,那么可以将其称为一个function(在大多数情况下,它对我来说是反function的,就像switch
语句一样),如果需要它, 。 如果是~~
意味着返回0
,所以要小心。
在某些情况下, parseInt()
可能会伤害到你。 厉害。 例如,如果数字太大以至于写成指数表示法。 然后使用Math
方法。
parseInt(2e30); // will return 2
无论如何,最后我想列出一个方法来将string转换为数字(整数和浮点数)。 他们有各种用法,你可能会感兴趣什么方法来使用。 在大多数情况下,最简单的是+number
方法,如果可以的话,使用它。 无论你做什么(除了第一种方法),都应该给出正确的结果。
parseInt('08', 10); // 8 +'08'; // 8 ~~'08'; // 8 parseFloat('08'); // 8 Number('08'); // 8 new Number('08'); // 8... I meant Object container for 8 Math.ceil('08'); // 8
parseInt(number)
不要使用。 就那么简单。 要么使用parseInt(number, 10)
或这个解决方法,这将奇迹般地解决parseInt
函数。 请注意,这种解决方法在JSLint中不起作用。 请不要抱怨。
(function () { "use strict"; var oldParseInt = parseInt; // Don't use function parseInt() {}. It will make local variable. parseInt = function (number, radix) { return oldParseInt(number, radix || 10); }; }());
parseInt(number, radix)
parseInt
使用上述algorithm将参数转换为数字。 避免在大整数上使用它,因为在parseInt(2e30)
等情况下,它可能会产生不正确的结果。 此外,永远不要把它作为Array.prototype.map
或Underscore.js变体的参数,因为你可能得到奇怪的结果(尝试['1', '2', '3'].map(parseInt)
如果你想(为了解释,用console.log
replaceparseInt
))。
在以下情况下使用它:
- 当您需要读取以不同基数写入的数据时。
- 您需要忽略错误(例如将
123px
更改为123
)
否则,使用其他更安全的方法(如果您需要整数,请改用Math.floor
)。
+number
+
前缀( +number
)将数字转换为浮点数。 如果发生错误,则返回NaN
,您可以通过isNaN()
或者仅仅通过number !== number
(只能为NaN
返回true
)来比较。 Opera的速度非常快。
除非你想要其他types的特定function,否则使用它。
~~number
~~
是一个在整数上使用~
两次的hack。 由于只能对整数进行按位操作,因此该数字会自动转换。 大多数浏览器都针对这种情况进行了优化。 由于按位运算只能在Math.pow(2, 32)
不要使用大数字的方法。 它在SpiderMonkey引擎上非常快速。
在以下情况下使用它:
- 您正在编写代码,其中性能对SpiderMonkey非常重要(如FireFox插件),您不需要检测错误。
- 您需要整数和小心产生的JavaScript大小。
parseFloat(number)
parseFloat()
工作原理与+
一样,只有一个例外 – 它处理数字直到第一个无效字符,而不是返回NaN
。 在V8中速度非常快(但不像Firefox上的速度快)。 与parseInt
变体不同, Array.prototype.map
应该是安全的。
在以下情况下使用它:
- 您正在为Node.js编写性能至关重要的代码,或者您正在编写Google Chrome插件(V8)。
- 您需要忽略错误(例如,将
42.13px
更改为42.13
)
Number(number)
躲开它。 它的作用就像+
前缀,通常比较慢。 唯一有用的地方是Array.prototype.map
callback – 你不能使用+
作为callback。
new Number(number)
当你需要混淆每个人为0
的真值和具有'number'
时使用它。 真的,不要。
math方法,如Math.ceil(number)
在需要整数时使用它们,因为它比parseInt()
更安全,不会忽略意外的字符。 请注意,从技术上讲,它涉及到很长的转换 – string→浮点→整数→浮点数(JavaScript中的数字是浮点数) – 但大多数浏览器都有优化,所以通常不会那么明显。 Array.prototype.map
也是安全的。
如果你知道你的值是在32位的有符号整数范围内,那么~~x
将在所有情况下做正确的事情。
~~"08" === 8 ~~"foobar" === 0 ~~(1.99) === 1 ~~(-1.99) === -1
如果你查找二进制不是( ~
),规范需要一个“ToInt32”转换的参数做了明显的转换到一个Int32,并指定强制NaN
值为零。
是的,这是令人难以置信的黑客,但是非常方便
从parseInt文档中 ,使用可选的基数参数来指定base-10:
parseInt('08', 10); //equals 8 parseInt('09', 10); //equals 9
这使我感到迂腐,混乱,冗长(真的,在每一个parseInt中额外的参数?),所以我希望有一个更好的方法。
function parseDecimal(s) { return parseInt(s, 10); }
编辑:做你自己的function,做你真正想要的,只是一个选项,如果你不喜欢把parseInt()调用添加“,10”。 它有一个不规范的function的缺点:如果你使用它很方便,但也许更容易混淆别人。
指定基地:
var number = parseInt(s, 10);
如果没有第二个参数,用一个假定为十进制的版本replaceparseInt会非常顽皮吗? (注 – 未经testing)
parseIntImpl = parseInt parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
小数点如何?
('09'-0) === 9 // true ('009'-0) === 9 // true
如果你已经用parseInt做了一堆编码,并且不想在所有内容中添加“,10”,那么你可以重写这个函数来使得base 10成为默认值:
window._oldParseInt = window.parseInt; window.parseInt = function(str, rad) { if (! rad) { return _oldParseInt(str, 10); } return _oldParseInt(str, rad); };
这可能会让后来的读者感到困惑,所以使用parseInt10()函数可能会更加明了。 就我个人而言,我更喜欢使用一个简单的函数,而不是一直添加“,10” – 只是为错误创造更多的机会。
您也可以不使用parseFloat或parseInt,而使用一元运算符+ 。
+"01" // => 1 +"02" // => 2 +"03" // => 3 +"04" // => 4 +"05" // => 5 +"06" // => 6 +"07" // => 7 +"08" // => 8 +"09" // => 9
并为好的措施
+"09.09" // => 9.09
MDN链接
一元加运算符在它的操作数之前,并且计算它的操作数,但是试图把它转换成一个数字(如果它还没有的话)。 尽pipe一元否定( – )也可以转换非数字,但一元加数是将某些东西转换为数字的最快和首选方式 ,因为它不会对数字执行任何其他操作。