请考虑以下代码:
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
是由字符串f+1–k
的字符的出现'0'
.我们
m
是字符串的串联z
和m
.我们
k = f + 1
.让我们
a
成为第一个k–f
角色m
,让b
剩下的f
角色成为m
.让
m
是三个字符串的串联a
,"."
和b
.返回字符串的连接
s
和m
.该方法的
length
属性toFixed
是1
.如果
toFixed
使用多个参数调用该方法,则行为未定义(请参阅第15节).允许实现扩展小于或大于的
toFixed
值的行为.在这种情况下 ,不一定会抛出这样的值.fractionDigits
0
20
toFixed
RangeError
注意输出
toFixed
可能比toString
某些值更精确,因为toString
只打印足够的有效数字以区分数字和相邻数字值.例如,(1000000000000000128).toString()
返回"1000000000000000100"
时(1000000000000000128).toFixed(0)
返回"1000000000000000128"
.
解决您的两个原始问题:
这里的问题在于误解这些应该总是给出相同的结果.事实上,它们受不同规则的约束.例如,查看负数.由于Math.round
采用"圆的一半了"作为规则,你会看到,Math.round(-1.5)
计算结果为-1
,即使Math.round(1.5)
计算结果为2
.
Number.prototype.toFixed
另一方面,根据规范的第6步,使用基本上相当于"从零开始的一半"的规则,基本上将负数视为正数,然后在负数上添加负数.结束.因此,并且是所有符合规范的浏览器中的真实陈述.请注意,这些值是字符串,而不是数字.进一步,无论注意和是(数量),由于运算符优先级.(-1.5).toFixed(0) === "-2"
(1.5).toFixed(0) === "2"
-1.5.toFixed(0)
-(1.5).toFixed(0)
=== -2
大多数现代浏览器 - 或者至少是你在撰写本文时可能会支持的 浏览器除了IE之外 -都应该正确实现规范.(根据Renee的评论,toFixed
你在Opera中指出的问题已得到解决,大概是因为他们开始使用与Chrome相同的JS引擎.)仍然值得重申的是,即使规范在所有浏览器中一致地实现,行为定义也是如此在规范中,特别是对于toFixed
舍入,对于那些期望真正的数学准确性的"凡人"JS开发人员来说仍然有点不直观 - 请参阅Javascript toFixed Not Rounding并且这个"按预期工作"的错误已经在V8 JS引擎上提交了示例.
简而言之,这是两个不同的函数,具有两种不同的返回类型和两组不同的舍入规则.
正如其他人所建议的那样,我还想说"使用适合您特定用例的任何函数"(特别注意注意特殊性toFixed
,尤其是IE的错误实现).我个人更倾向于推荐一些明确的组合 编辑: ...但是,在回过头来阅读你的澄清之后,你的用例(四舍五入到一个整数)肯定需要一个恰当命名的Math.round/ceil/floor
,再次,正如其他人所提到的那样.Math.round
函数.
toFixed()返回一个字符串值.来自Javascript:The Definitive Guide
将数字转换为包含小数位后指定位数的字符串.
Math.round()返回一个整数.
显然,toFixed()似乎更多用于赚钱,例如,
'$'+ 12.34253.toFixed(2)='$ 12.34'
很遗憾toFixed()似乎没有正确圆!