JavaScript中的(怪异)数字转换背后的秘密是什么?
我已经设法在下面给出的几个测试用例中找出一些使用isnumeric
函数的函数。
//
function isnumeric(n) {
try {
return (isFinite(n = n.valueOf()) || ((1 / 0 === Math.abs(n)) && (n + n === n)))
&& eval(n) === parseFloat(Number(n));
} catch (b) {}
return false;
}
console.clear();
[
.1, 1, 0, "0", Infinity, 1/0, -1/0, +null, 01, 037, 1 + [],
Math.pow([], 2), 0xff, 0x12ef, +[], -[], -1/[], []/Infinity,
"0x12", 1/null, null/1, Math.sqrt([]), []/1, Infinity/[], new Date,
Math.E, "1.2e-12", 0.1e11, null + +[], Math.sqrt(null), 1/"\t\r\n ",
" \t\r\n\uFEFF\xA0\x0B\u2028\u2029\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000"/1
].every(isnumeric);
//
// true
//
isFinite(n = n.valueOf())
处理类似数字的值(字符串,数字,日期),
(1 / 0 === Math.abs(n)) && (n + n === n)
从(字符串)Infinity
过滤掉"Infinity"
,
eval(n) === parseFloat(Number(n))
部分处理 string-numerics 持有字符:“x,e”等。
谢谢!
答案 0 :(得分:4)
由于我真的不知道你在问什么,我只会回答所有问题。
n.valueOf
如果将数字对象(而不是数字原语)传递给函数,则完成此调用:
var numObj = new Number(4),
numPrim = 4;
console.log(typeof numObj, typeof numPrim); //object, number
numObj === numPrim; //false
//however:
numObj.valueOf() === numPrim; //true
isFinite
isFinite(arg)
将arg
转换为数字(我将稍后介绍),并检查它是否不是NaN,+∞或-∞之一:
isFinite(4); //true
isFinite(Infinity); //false
isFinite("Infinity"); //false (the argument is converted into a number)
isFinite("foobar"); //false (converting a random string to a number yields NaN
(1 / 0 === Math.abs(n))
1/0
给我们带来+∞,所以这会检查参数是+∞还是-∞。 Infinity
电话中发现了isFinite
(请注意这是多么奇怪:isFinite
被用作修剪因素......但我们仍然希望Infinity
成为一个数字)
(n + n === n)
同样,这会抓住Infinity
,因为它是满足这个等式的唯一值(没有检查,但它有意义;我最后会谈到它)。真的很无用。
eval(n) === parseFloat(Number(n))
(parseFloat:spec,mdn) (编号:spec,mdn)。
这是一个奇怪的兔子。背后的原因超出了我的想法。左侧执行n
,就像它是js一样,右手将n
转换为数字。两次。希望实现的目标可能是捕获NaN
或无效的数字字符串。
它属于冗余部门,原因如下:
Number
调用内部ToNumber
函数,该函数将参数转换为基于js'语法的数字。因此,如果参数是无效数字,则返回值将为NaN
。 eval
最后会做同样的事情,但开销会更大。
对parseFloat
的外部呼叫是荒谬的。 parseFloat
将其参数转换为字符串,然后尝试查看字符串是否以有效数字开头。这已经在Number
中完成,这也比parseFloat
更严格(因为前者要求整个字符串是有效数字,而不仅仅是开头)。
ToNumber
已在isFinite
中调用。如果参数为NaN
或字符串不是数字,我们就会得到false
。
所以这个函数包含不需要的重复和一些不合逻辑的调用。取自this great answer,可以写成:
function isNumeric (n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
ToNumber
当你执行4 * []
时,会发生什么(section 11.5)是运营商的每一方都被转换为一个数字,然后计算出答案。他们如何转换为数字?那是在section 9.3, the ToNumber
function。在大多数情况下,您会看到奇怪的行为,这是因为您使用对象作为要操作的值之一,并且该对象将转换为字符串(有关示例,请参阅this question)。