JavaScript中能否使用toLocaleString()截断数字且不触发四舍五入?
问题根因
返回值异常和两个因素直接相关:
- JavaScript的
Number类型是64位双精度浮点数,十进制的9.95无法被二进制精确存储,实际内存中的值约为9.950000000000001,本身略大于字面量标注的9.95。 - 核心原因是当前使用的运行时没有实现
toLocaleString底层依赖的Intl.NumberFormat的roundingMode参数,传入的trunc配置被静默忽略,走了默认的四舍五入逻辑,略大于9.95的存储值被进位后就输出了10.0。
你当前用的(9.95).toString().substring(0,3)写法鲁棒性极差,遇到多位数整数、负数、小于1的小数都会返回错误结果,比如10.95会被截成"10",-9.95会被截成"-9.",不建议使用。
可靠实现方案
方案1:新版运行时标准写法
如果你使用的Deno版本在1.25及以上(对应Chrome 106+、Node 19+),roundingMode参数可以正常生效,直接使用标准配置即可:
const formatResult = (9.95).toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1, roundingMode: "trunc" }); // 正常输出 "9.9"
方案2:全环境兼容写法
如果需要兼容不支持roundingMode的旧运行时,先用数学方法完成截断,再做本地化格式化,完全规避API的舍入逻辑问题:
/** * 按指定位数截断小数,不做四舍五入 * @param {number} num 待处理数值 * @param {number} places 保留小数位数 * @returns {number} 截断后的数值 */ function truncDecimal(num, places) { const scale = 10 ** places; return Math.trunc(num * scale) / scale; } const truncatedVal = truncDecimal(9.95, 1); const formatResult = truncatedVal.toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 }); // 所有环境均输出 "9.9"
补充说明
如果是处理金额这类对精度要求极高的场景,不要直接用原生Number做运算,建议先将数值转成最小货币单位的整数(比如人民币转成分)计算后再转译,避免浮点数精度误差导致的资损问题。
内容的提问来源于stack exchange,提问作者Brass P.
相关产品推荐
相关产品推荐

