如何在 JavaScript 中舍入一个数字? .toFixed() 返回一个字符串?
Posted
技术标签:
【中文标题】如何在 JavaScript 中舍入一个数字? .toFixed() 返回一个字符串?【英文标题】:How can I round a number in JavaScript? .toFixed() returns a string? 【发布时间】:2011-01-18 00:29:54 【问题描述】:我错过了什么吗?
var someNumber = 123.456;
someNumber = someNumber.toFixed(2);
alert(typeof(someNumber));
//alerts string
为什么.toFixed()
返回一个字符串?
我想将数字四舍五入为 2 位小数。
【问题讨论】:
因为它被设计成返回一个字符串? 对我来说这似乎很奇怪。 .toFixed() 只对数字起作用……对吧? 我了解 Math.round() 可以按预期工作。我只是在询问为什么对数字进行操作的函数会返回一个字符串... 生活在 2017 年的人们应该使用像 lodash.com/docs/4.17.4#ceil 这样的库 _也是如此。数数?还没有升级到他的兄弟。 【参考方案1】:当然它返回一个字符串。如果您想对数值变量进行四舍五入,请改用 Math.round()。 toFixed 的重点是将数字格式化为固定小数位数以显示给用户。
【讨论】:
【参考方案2】:当它应该格式化一个数字时,你希望它返回什么?如果你有一个数字,你几乎不能用它做任何事情,因为例如2 == 2.0 == 2.00
等,所以它必须是一个字符串。
【讨论】:
【参考方案3】:因为它的主要用途是显示数字?如果要对数字进行四舍五入,请使用带有适当因数的Math.round()
。
【讨论】:
但它显示的是 NUMBERS 所以它不应该返回一个“数字”吗? @Derek:只是因为'42'
是一个数字......它不是。仅仅因为一个字符串恰好包含数字并不能使它成为一个数字。这不是 php。 :-P
哈哈。它不是包含数字的字符串......它是传递给方法的数字。该方法接受一个数字并返回一个字符串。
@DerekAdair 对,但浏览器无法显示数字,它显示字符串,因此转换。【参考方案4】:
它返回一个字符串,因为 0.1 及其幂(用于显示小数)在二进制浮点系统中不可表示(至少不能完全准确)。
例如,0.1 真的是 0.1000000000000000055511151231257827021181583404541015625,而 0.01 真的是 0.01000000000000000020816681711721686712940859378 (感谢BigDecimal
证明了我的观点。:-P)
因此(没有十进制浮点或有理数类型),将其作为字符串输出是使其精确到显示所需精度的唯一方法。
【讨论】:
至少 javascript 可以为我节省一些手指工作并将其转换回一个数字...嘘... @Derek:是的,但是一旦将其转换回数字,您就会再次遇到同样的不准确问题。 :-P JS 没有十进制浮点数或有理数。 @DerekAdair 我最近写了一篇文章,进一步解释了这一点,你可能会感兴趣。享受吧! ***.com/a/27030789/13 实际上,这让我对这个主题做了一些相当深入的研究!感谢您的所有帮助! 您的回答有点误导:toFixed
是一个格式化函数,其唯一目的是将数字转换为字符串,并使用指定的小数位数对其进行格式化。它返回一个字符串的原因是因为它应该返回一个字符串,如果它被命名为toStringFixed
,OP 不会对结果感到惊讶。这里唯一的问题是 OP 希望它像 Math.round
一样工作,而无需咨询 JS 参考。【参考方案5】:
我通过改变这个解决了这个问题:
someNumber = someNumber.toFixed(2)
...到这个:
someNumber = +someNumber.toFixed(2);
但是这会将数字转换为字符串并再次对其进行解析,这将对性能产生重大影响。如果您关心性能或类型安全,请同时查看其他答案。
【讨论】:
不,不,不,不,不! 不要那样做!数字到字符串的转换只是为了舍入它是一个非常糟糕的做法!而是做someNumber = Math.round(someNumber * 1e2) / 1e2
!请参阅我的答案以获得更通用的方式。
@jczaplew 因为如果你这样做,32 位二进制数将被转换成一个字符串,每个该死的十进制 digit 使用 16 位! (顺便说一下,在 UTF-16 中存储数字并不是最方便的事情。)然后字符串被转换回 32 位浮点数。一个个数字。 (如果我忽略了在选择正确的解析算法之前必须完成的所有测试。)考虑到您可以在浮点数上使用 3 个快速操作来完成,所有这些都是徒劳的。
@m93a 所以这是出于性能原因?这实际上对性能有显着影响吗?
@jczaplew,因为字符串(1)实际上很慢,(2)理论上不正确。
Math.round(someNumber * 1e2) / 1e2
很容易记住。 JavaScript 太有趣了???【参考方案6】:
我通过使用 JavaScript 的 Number()
函数将其转换回数字来解决它
var x = 2.2873424;
x = Number(x.toFixed(2));
【讨论】:
【参考方案7】:Number.prototype.toFixed
是一个用于在打印出来之前格式化数字的函数。它来自toString
、toExponential
和toPrecision
家族。
要对数字进行四舍五入,您可以这样做:
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-like”的功能,你可以扩展原型:
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";
然而,请记住,在编写模块时污染原型被认为是不好的,因为模块不应该有任何副作用。所以,对于一个模块,使用第一个函数。
【讨论】:
我认为这是最好的答案。它避免了类型转换。太棒了! 很好的答案!但是......我已经做了 20 年左右的 JavaScript,但我不明白你为什么在返回值周围使用 +(...) 构造?感谢@sam 把它揉进去:) 因为我从来没有老到不能学习,请详细说明:-) @HammerNL 尽管 Sam 坚信这一点,但它实际上并没有做任何事情 :) 这只是一种实践——它使 IDE 将这个函数识别为type Number
。问题是+(anyValue)
总是返回一个数字——例如。 +("45")
返回 45
,+(new Number(42))
返回 42
。这有点像函数的强类型。如果你养成它的习惯,你可以避免很多错误:)
为什么这没有融入核心 javascript :s
someNumber = Math.round( 42.008 * 1e2 ) / 1e2;
的结果不是42.01
,而是~42.0099999999999980
。原因:数字42.01
不存在,四舍五入到最接近的现有数字。顺便说一句,toPrecision(18)
的证明编号用所有相关数字打印出来。【参考方案8】:
为什么不使用parseFloat
?
var someNumber = 123.456;
someNumber = parseFloat(someNumber.toFixed(2));
alert(typeof(someNumber));
//alerts number
【讨论】:
或者简单地用 + 号代替 parseFloat() 来转换成数字。【参考方案9】:您可以简单地使用“+”将结果转换为数字。
var x = 22.032423;
x = +x.toFixed(2); // x = 22.03
【讨论】:
【参考方案10】:这是答案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 return 0; 【参考方案11】:提供一个为什么它必须是字符串的例子:
如果你格式化 1.toFixed(2) 你会得到 '1.00'。
这与 1 不同,因为 1 没有 2 个小数。
我知道 JavaScript 并不完全是一种 性能 语言,但如果您使用以下内容,您可能会在舍入时获得更好的性能: roundedValue = Math.round(value * 100) * 0.01
【讨论】:
【参考方案12】:对于像我这样遇到这个非常古老的问题的人来说,一个现代的解决方案:
const roundValue = (num, decimals = 2) =>
let scaling = 10 ** decimals;
return Math.round((num + Number.EPSILON) * scaling) / scaling;
参考:https://***.com/a/11832950
【讨论】:
【参考方案13】:回答可能为时已晚,但您可以将输出与 1 相乘以再次转换为数字,这是一个示例。
const x1 = 1211.1212121;
const x2 = x1.toFixed(2)*1;
console.log(typeof(x2));
【讨论】:
【参考方案14】:你应该像下面这样使用它。
var someNumber: number = 0.000000;
someNumber = Number(someNumber.toFixed(2))
【讨论】:
【参考方案15】:为什么不将结果 * 1 即
someNumber.toFixed(2) * 1
【讨论】:
以上是关于如何在 JavaScript 中舍入一个数字? .toFixed() 返回一个字符串?的主要内容,如果未能解决你的问题,请参考以下文章