Math.round(num)与num.toFixed(0)和浏览器不一致
考虑下面的代码:
for (var i=0;i<3;i++){
var num = i + 0.50;
var output = num + " " + Math.round(num) + " " + num.toFixed(0);
alert(output);
}
在Opera 9.63中,我得到:
0.5 1 0
1.5 2 2
2.5 3 2
在FF 3.03中,我得到:
0.5 1 1
1.5 2 2
2.5 3 3
在IE 7中,我得到:
0.5 1 0
1.5 2 2
2.5 3 3
注意粗体结果。 为什么存在这种不一致? 这是否意味着toFixed(0)
应该被避免? 将数字四舍五入到最接近的整数的正确方法是什么?
编辑:要回答您的编辑,请使用Math.round
。 如果你喜欢这种语法,你也可以原型化Number
对象,让它做你的出价。
Number.prototype.round = function() {
return Math.round(this);
}
var num = 3.5;
alert(num.round())
我之前从未使用Number.toFixed()
(主要是因为大多数JS库提供了toInt()
方法),但根据您的结果来判断,我会说使用Math
方法( round
, floor
, ceil
)会更一致。然后toFixed
如果跨浏览器一致性是你正在寻找。
我认为FF用toFixed做了正确的事情,因为下面的第10步说“如果有两个这样的n,选择较大的n”。
正如Grant Wagner所说:使用Math.ceil(x)或Math.floor(x)代替x.toFixed()。
以下全部内容来自ECMAScript语言规范:
15.7.4.5 Number.prototype.toFixed (fractionDigits)
返回一个字符串,其中包含以小数点后的fractionDigits
数字表示的以定点表示法表示的数字。 如果fractionDigits
未定义,则假定为0
。 具体来说,执行以下步骤:
f
为ToInteger(fractionDigits)
。 (如果fractionDigits
未定义,则此步骤会生成值0
)。 f < 0
或f > 20
,则引发RangeError
异常。 x
是这个数字值。 x
是NaN
,则返回字符串"NaN"
。 s
为空字符串。 x ≥ 0
,请转至步骤9。 "-"
。 x = –x
。 x ≥ 10^21
,让m = ToString(x)
并转到步骤20。 n
是一个整数,其精确的数学值n ÷ 10^f – x
尽可能接近于零。 如果有两个这样的n
,选择较大的n
。 n = 0
,则让m
为字符串"0"
。 否则,设m
为由n
的十进制表示形式的数字组成的字符串(按顺序,没有前导零)。 f = 0
,则转到步骤20。 k
为m
的字符数。 k > f
,请转至步骤18。 z
是由字符'0'
的f+1–k
次出现组成的字符串。 m
是串z
和m
的串联。 k = f + 1
。 a
是m
的前k–f
字符,设b
是m
的剩余f
字符。 m
是三个字符串a
, "."
,和b
。 s
和m
的连接。 toFixed
方法的length
属性为1
。
如果使用多个参数调用toFixed
方法,则行为未定义(请参见第15节)。
一个实现允许扩展toFixed
的行为,以便小于0
或大于20
的fractionDigits
值。 在这种情况下toFixed
不一定会为这些值抛出RangeError
。
注 :对于某些值, toFixed
的输出可能比toString
更精确,因为toString
只打印足够的有效数字以区分相邻数值的数字。 例如, (1000000000000000128).toString()
返回"1000000000000000100"
,而(1000000000000000128).toFixed(0)
返回"1000000000000000128"
。
解决您的两个原始问题/问题:
Math.round(num)vs num.toFixed(0)
这里的问题在于它们应该总是给出相同结果的错误观念。 事实上,它们受不同规则的约束。 例如,看负数。 由于Math.round
使用“半舍起”作为规则,因此即使Math.round(1.5)
计算结果为2
, Math.round(-1.5)
计算结果也为-1
。
另一方面, Number.prototype.toFixed
使用基本上等同于“离零的一半的距离”的规则,根据规范的步骤6,基本上说,将负数视为正数,然后加回最后的负号。 因此, (-1.5).toFixed(0) === "-2"
和(1.5).toFixed(0) === "2"
是所有符合规范的浏览器中的真实语句。 请注意,这些值是字符串,而不是数字。 进一步注意,由于运算符的优先级, -1.5.toFixed(0)
和-(1.5).toFixed(0)
都是=== -2
(数字)。
浏览器不一致
大多数现代浏览器 - 或者至少在本文编写时应该支持的浏览器除外 -都应该正确实现规范。 (根据Renee的评论,你在Opera中指出的toFixed
问题已经修复,大概是因为他们开始使用与Chrome相同的JS引擎。)仍然值得重申的是,即使规范在所有浏览器中一致地实现,行为在规范中定义的,特别是对于toFixed
四舍五入,仍然可以对谁想到“凡人” JS开发商有点不直观的真实数字的精确性,看到的Javascript toFixed不圆整而这个“作品意欲”错误,是在V8 JS引擎提交举些例子。
结论
总之,这些是两种不同的功能,具有两种不同的返回类型和两套不同的舍入规则。
正如其他人所建议的,我还想说“使用适合您的特定用例的功能”(特别注意toFixed
的特性,特别是IE的错误实现)。 正如其他人所提到的,我个人更倾向于推荐Math.round/ceil/floor
明确组合。 编辑:...然而,在回头阅读你的说明之后,你的用例(四舍五入为整数)肯定会要求命名为Math.round
函数。
上一篇: Math.round(num) vs num.toFixed(0) and browser inconsistencies