如何在JavaScript中舍入数字?.toFixed()返回字符串?


174

我在这里想念什么吗?

var someNumber = 123.456;
someNumber = someNumber.toFixed(2);
alert(typeof(someNumber));
//alerts string

为什么.toFixed()返回一个字符串?

我想将数字四舍五入为2个小数位数。


7
因为它被设计为返回字符串?
kennytm 2010年

2
对我来说,这似乎很奇怪。.toFixed()仅适用于数字...对吗?
德里克·阿黛尔

10
我了解Math.round()可以正常工作。我只是在问为什么对数字进行运算的函数会​​返回字符串...
Derek Adair 2010年

3
生活在2017年的人应该使用库像lodash.com/docs/4.17.4#ceil
伊夫·M.

1
_也是如此。计数?还没有升级到他的兄弟。
珍娜·叶

Answers:


124

它之所以返回一个字符串,是因为在二进制浮点系统中,0.1及其幂(用于显示十进制小数)不能表示(至少不能完全准确)。

例如,0.1实际上是0.1000000000000000055511151231257827021181583404541015625,而0.01实际上是0.01000000000000000020816681711721685132943093776702880859375。(感谢您BigDecimal证明我的观点。:-P)

因此(缺少十进制浮点数或有理数类型),将其输出为字符串是将其修整到精确显示所需精度的唯一方法。


28
至少JavaScript可以为我省去一些麻烦,然后将其转换回数字...嘘...
Derek Adair 2010年

10
@Derek:是的,但是一旦将其转换回数字,就会再次遇到相同的不准确性问题。:-P JS没有十进制浮点数或有理数。
克里斯·杰斯特·杨

1
@DerekAdair我最近写了一篇帖子,进一步解释了这一点,您可能对此感兴趣。stackoverflow.com/a/27030789/13
克里斯·杰斯特·杨

7
实际上,这使我对这个主题进行了相当多的研究!感谢你的帮助!
德里克·阿黛尔

2
您的答案有点令人误解:这toFixed是一种格式化功能,其唯一目的是将数字转换为字符串,并使用指定的小数位数对其进行格式化。它返回一个字符串的原因是因为它应该返回一个字符串,并且如果它被命名toStringFixed,OP不会对结果感到惊讶。这里唯一的问题是OP希望它能像一样工作Math.round,而无需参考JS参考。
Groo

176

Number.prototype.toFixed是一项旨在在打印之前格式化数字的功能。这是来自家庭的toStringtoExponentialtoPrecision

要舍入一个数字,您可以这样做:

someNumber = 42.008;
someNumber = Math.round( someNumber * 1e2 ) / 1e2;
someNumber === 42.01;

// if you need 3 digits, replace 1e2 with 1e3 etc.
// or just copypaste this function to your code:

function toFixedNumber(num, digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(num*pow) / pow;
}

或者,如果您想要一个“ 类似native ”的函数,可以扩展原型:

Number.prototype.toFixedNumber = function(digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(this*pow) / pow;
}
someNumber = 42.008;
someNumber = someNumber.toFixedNumber(2);
someNumber === 42.01;


//or even hexadecimal

someNumber = 0xAF309/256  //which is af3.09
someNumber = someNumber.toFixedNumber(1, 16);
someNumber.toString(16) === "af3.1";

但是,请记住,编写模块时认为污染原型是不好的,因为模块不会产生任何副作用。因此,对于模块,请使用第一个功能


12
我认为这是最好的答案。它避免了类型转换。很棒的酱!
Phil

1
好答案!但是...我从事JavaScript已有20多年了,但我不知道为什么您在返回值周围使用+(...)构造?感谢@sam将其揉入:)由于我永远不会老到学到,请详细说明:-)
HammerNL

1
@HammerNL尽管Sam坚信,但它实际上并没有执行任何操作:)这只是一种实践–它使IDE将此功能识别为type Number。问题是+(anyValue)总是返回一个数字-例如。+("45")返回45+(new Number(42))返回42。这有点像强键入该函数。如果您养成习惯,则可以避免很多错误:)
m93a

为什么不将其纳入核心javascript:s
网站管理员

2
结果someNumber = Math.round( 42.008 * 1e2 ) / 1e2;不是42.01,而是~42.0099999999999980。原因:该号码42.01不存在,并四舍五入到最接近的现有号码。顺便说一句,按证明号toPrecision(18)打印所有相关数字。
Wiimm

118

我通过更改此方法解决了这个问题:

someNumber = someNumber.toFixed(2)

...对此:

someNumber = +someNumber.toFixed(2);

但是,这会将数字转换为字符串,然后再次对其进行解析,这将对性能产生重大影响。如果您关心性能或键入安全性,请同时检查其他答案。


39
不,不,不,不,不!不要那样做!仅将数字转换为字符串是很不好的做法!反而做someNumber = Math.round(someNumber * 1e2) / 1e2!请参阅我的答案,以获得更一般的方法。
m93a 2015年

@ m93a-为什么这么不好?
jczaplew '16

3
@jczaplew因为如果这样做,则32位二进制数将转换为字符串,每个该死的十进制数字都使用16 !(通过这种方式将数字存储在UTF-16中并不是您想要的最方便的方法。)然后将字符串转换回32位浮点数。逐位数。(如果我忽略了选择正确的解析算法之前必须完成的所有测试。)考虑到可以使用浮点数上的3个快速操作来做到这一点,都是徒劳的。
m93a 2013年

2
@ m93a是出于性能原因吗?这实际上对性能有明显影响吗?
塞巴斯蒂安

2
@jczaplew,因为字符串实际上(1)较慢,并且(2)理论上不正确。
Pacerier '17

28

为什么不使用parseFloat

var someNumber = 123.456;
someNumber = parseFloat(someNumber.toFixed(2));
alert(typeof(someNumber));
//alerts number

15

我通过使用JavaScript Number()函数将其转换回数字来解决它

var x = 2.2873424;
x = Number(x.toFixed(2));

12

当然,它返回一个字符串。如果要舍入数值变量,可以使用Math.round()代替。toFixed的要点是使用固定的小数位数格式化数字,以显示给用户


4

您可以简单地使用“ +”将结果转换为数字。

var x = 22.032423;
x = +x.toFixed(2); // x = 22.03

3

如果要格式化数字,您希望它返回什么?如果您有一个数字,那么您几乎不能做任何事情,因为例如2 == 2.0 == 2.00等,所以它必须是一个字符串。


3

提供一个为什么它必须是字符串的示例:

如果格式化1.toFixed(2),将得到'1.00'。

这与1不同,因为1没有2位小数。


我知道JavaScript并非完全是一种性能语言,但是如果使用类似以下内容,则可能会获得更好的舍入性能:roundedValue = Math.round(value * 100)* 0.01


2

因为它的主要用途是显示数字?如果要舍入数字,请使用Math.round()适当的因子。


但是它显示的是NUMBERS,因此它不应该返回“数字”吗?
德里克·阿黛尔

3
@Derek:只是以数字的方式'42'……不是。仅仅因为一个字符串碰巧只包含数字并不能使它成为数字。这不是PHP。:-P
Chris Jester-Young 2010年

大声笑。它不是包含数字的字符串,而是传递给方法的数字。该方法接受一个数字并返回一个字符串。
德里克·阿黛尔

@DerekAdair正确,但是浏览器无法显示数字,而是显示字符串,因此无法进行转换。
Nick M

1

这是所m93a提供答案的稍微实用的版本。

const toFixedNumber = (toFixTo = 2, base = 10) => num => {
  const pow = Math.pow(base, toFixTo)
  return +(Math.round(num * pow) / pow)
}

const oneNumber = 10.12323223

const result1 = toFixedNumber(2)(oneNumber) // 10.12
const result2 = toFixedNumber(3)(oneNumber) // 10.123

// or using pipeline-operator
const result3 = oneNumber |> toFixedNumber(2) // 10.12

它是一个方便的函数,对于未定义的类型它不起作用,我为这种情况添加了代码;if(num!== undefined){return +(Math.round(num * pow)/ pow)} else {返回0; }
Dino Liu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.