这些库旨在将原始数值转换为人类可读的字符串格式,涵盖货币符号、千位分隔符、百分比及科学计数法等场景。d3-format 和 mathjs 是目前维护活跃的主流选择,分别侧重于数据可视化精度和复杂数学运算后的格式化。accounting-js 和 numeral 属于早期经典库,但目前已停止维护。sprintf-js 侧重于 C 风格字符串插值,而 format-number 则提供轻量级的基础格式支持。
在前端开发中,将原始数值转换为用户友好的格式(如货币、百分比、千位分隔)是常见需求。虽然现代浏览器提供了原生 Intl.NumberFormat API,但在处理复杂场景、旧浏览器兼容或特定生态系统(如 D3)时,第三方库仍有其价值。本文将深度对比 accounting-js、d3-format、format-number、mathjs、numeral 和 sprintf-js,帮助你做出架构决策。
在选择库之前,必须了解其维护状态。使用已停止维护的库会引入安全风险和技术债务。
numeral 和 accounting-js 属于早期经典库,但目前已进入停止维护状态。
numeral 最后更新停留在数年前,社区已普遍建议迁移。accounting-js 功能单一,多年无版本迭代。d3-format 和 mathjs 是活跃维护的库。
d3-format 作为 D3 生态的一部分,更新频繁,稳定性高。mathjs 持续更新,适合科学计算场景。sprintf-js 和 format-number 处于稳定期。
💡 建议:除非维护旧系统,否则避免在新项目中使用
numeral和accounting-js。
货币格式化是最常见的需求,涉及符号、千位分隔和小数位数。
accounting-js 提供专用的货币函数,API 非常直观。
import accounting from 'accounting-js';
// 格式化为货币
const money = accounting.formatMoney(1234567.89, '$', 2);
// 输出:$1,234,567.89
d3-format 使用格式说明符字符串,灵活性极高。
import { format } from 'd3-format';
// 定义格式:美元,千位分隔,2 位小数
const usd = format('$,.2f');
const money = usd(1234567.89);
// 输出:$1,234,567.89
numeral 使用链式调用和模板字符串(已弃用,仅作对比)。
import numeral from 'numeral';
// 链式格式化
const money = numeral(1234567.89).format('$0,0.00');
// 输出:$1,234,567.89
mathjs 主要通过配置对象控制精度,货币符号需手动处理。
import { format } from 'mathjs';
// 控制精度,符号需自行拼接
const num = format(1234567.89, { precision: 2 });
const money = '$' + num.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 输出:$1,234,567.89 (需额外处理千位符)
sprintf-js 使用 C 风格占位符,不直接支持货币符号。
import sprintf from 'sprintf-js';
// 仅处理数字结构,符号需手动添加
const num = sprintf('%0,.2f', 1234567.89);
const money = '$' + num;
// 输出:$1,234,567.89
format-number 提供简单的选项对象配置。
import formatNumber from 'format-number';
// 通过配置对象控制
const formatter = formatNumber({ style: 'currency', currency: 'USD' });
const money = formatter(1234567.89);
// 输出:$1,234,567.89 (依赖底层实现)
不同库对小数舍入的处理方式不同,这在金融场景中至关重要。
d3-format 支持多种舍入类型(如向上、向下、最近)。
import { formatRound } from 'd3-format';
// 强制四舍五入
const round = formatRound('.2f');
console.log(round(1.235)); // 1.24
mathjs 允许指定有效数字位数,适合科学计算。
import { format } from 'mathjs';
// 指定有效数字精度
console.log(format(12345, { precision: 3 })); // 1.23e+4
numeral 默认四舍五入,但配置项有限。
import numeral from 'numeral';
console.log(numeral(1.235).format('0.00')); // 1.24
accounting-js 默认四舍五入,可配置精度。
import accounting from 'accounting-js';
console.log(accounting.formatMoney(1.235, '', 2)); // 1.24
sprintf-js 遵循标准 C 库舍入规则。
import sprintf from 'sprintf-js';
console.log(sprintf('%.2f', 1.235)); // 1.24
format-number 通常封装了原生行为,配置较简单。
import formatNumber from 'format-number';
const formatter = formatNumber({ round: 2 });
console.log(formatter(1.235)); // 1.24
除了数字格式化,库的通用性和与其他工具的集成能力也是考量点。
d3-format 是数据可视化领域的标准。
d3-scale、d3-axis 无缝配合。mathjs 是数学计算的全能工具。
sprintf-js 专注于字符串插值。
numeral / accounting-js / format-number 专注于数字。
| 特性 | d3-format | mathjs | sprintf-js | numeral | accounting-js | format-number |
|---|---|---|---|---|---|---|
| 维护状态 | ✅ 活跃 | ✅ 活跃 | ✅ 稳定 | ❌ 停止维护 | ❌ 停止维护 | ⚠️ 低频 |
| 主要用途 | 数据可视化 | 科学计算 | 字符串插值 | 通用格式化 | 货币格式化 | 轻量格式化 |
| API 风格 | 格式说明符 | 配置对象 | C 风格占位符 | 链式调用 | 专用函数 | 配置对象 |
| 包体积 | 小 | 大 | 极小 | 中 | 小 | 极小 |
| 推荐指数 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ 不推荐 | ❌ 不推荐 | ⭐⭐ |
首选方案:对于大多数现代前端项目,优先使用原生 Intl.NumberFormat。它无需依赖,支持所有主流浏览器,且性能最佳。
特定场景选择:
d3-format。它与图表库配合最好,格式控制最精细。mathjs。如果你已经用它做计算,顺便用它格式化可以减少依赖。sprintf-js。当你需要类似后端的字符串格式化逻辑时。numeral 或 accounting-js,建议制定计划迁移至 d3-format 或原生 API,以避免未来兼容性风险。最终结论:库的选择应基于项目具体需求。不要为了简单的数字格式化引入重型库(如 mathjs),也不要在新项目中使用已停止维护的库(如 numeral)。保持依赖精简,优先利用原生能力。
该库已正式停止维护,存在潜在的安全和兼容性风险。严禁在新项目中使用,现有项目应计划迁移至 d3-format 或原生 Intl.NumberFormat。
适用于只需要简单数字分隔且不希望引入重型依赖的场景。它的 API 直观,但功能相对基础,适合轻量级工具库。
适合维护旧项目,它提供了开箱即用的货币格式化功能,代码简单直观。但由于已多年未更新,缺乏对现代 locale 标准的支持,不建议在新架构中引入。
如果你正在构建数据可视化应用或需要极高的格式控制精度,这是首选。它维护活跃,支持复杂的格式说明符,且与 D3 生态系统无缝集成。
仅当你已经需要用到其强大的数学计算功能(如矩阵运算、单位转换)时才选择它。单纯为了格式化而引入它会导致包体积过大,得不偿失。
当你需要类似 C 语言 printf 的字符串插值功能时使用,不仅仅是数字,还包括日期、对象等。它适合日志格式化或复杂模板字符串构建。
A javascript library for formatting and manipulating numbers.
#CDNJS
develop branch. All pull requests must include the appropriate tests.Fork the library
Run npm install to install dependencies
Create a new branch from develop
Add your tests to the files in /tests
To test your tests, run grunt
When all your tests are passing, run grunt dist to compile and minify all files
Submit a pull request to the develop branch.
Formats now exist in their own files and act more or less as plugins. Check out the bytes format for an example of how to create one.
When naming locale files use the ISO 639-1 language codes supplemented by ISO 3166-1 country codes when necessary.
See the english unit tests for an example.
Bug fix: Multi letter currency symbols and spacing
Added: Formatting of numbers with leading zeros
New format: Basic Point
Option: Added scalePercentBy100 (default: true) option to turn on/off scaling percentages
Bug fix: Incorrect abbreviations for values rounded up #187
Bug fix: Signed currency is inconsistent #89
Bug fix: Updated module definitions
Bug fix: Fixed regression for webpack/browserify/rollup
2.0.0 brings a lot of breaking changes and a reorganization of the repo, but also simplifies the api as well as the creating of custom formats.
Breaking change / Feature: All formats are now separate files. This makes it easy to create custom formats, and will also allow for custom builds with only certain formats. (Note: The built numeral.js still contains all formats in the repo).
Breaking change / Feature: All formats and locales are now loaded using numeral.register(type, name, {})
Breaking change: All language now renamed to locale and standardized to all lowercase filenames
Breaking change: The locale function no longer loads locales, it only sets the current locale
Breaking change: The unformat function has been removed numeral().unformat(string) and now happens on numeral init numeral(string)
Breaking change / Feature: Bytes are now formatted as: b (base 1000) and ib (base 1024)
Breaking change: numeral(NaN) is now treated the same as numeral(null) and no longer throws an error
Feature: Exponential format using e+ or e-
Bug fix: Update to floating point helpers (Note: Numeral does not fix JS floating point errors, but look to our tests to see that it covers quite a few cases.)
Bug fix: numeral converts strings to numbers
Bug fix: Null values return same as 0
Contained breaking changes, recommended to use 1.5.6
Bug fix: Switch bytes back to b and change iecBinary to ib, and calculate both using 1024 for backwards compatibility
Contained breaking changes, recommended to use 1.5.6
Tests: Changed all tests to use Mocha and Chai
Tests: Added browser tests for Chrome, Firefox, and IE using saucelabs
Added reset function to reset numeral to default options
Added nullFormat option
Update reduce polyfill
Added Binary bytes
Bug fix: Fixes problem with many optional decimals
Added currency symbol to optionally appear before negative sign / open paren
Added float precision math support
Added specification of abbreviation in thousands, millions, billions
Bug fix: Unformat should pass through if given a number
Added a mechanism to control rounding behaviour
Added languageData() for getting and setting language props at runtime
Bug fix: Make sure values aren't changed during formatting
Add defaultFormat(). numeral().format() uses the default to format if no string is provided
.unformat() returns 0 when passed no string
Added languages.js that contains all languages
Bug fix: Fix bug while unformatting ordinals
Add format option to always show signed value
Added ability to instantiate numeral with a string value of a number
Bug fix: Fix bug while unformatting ordinals
Bug fix: Throw error if language is not defined
Bug fix: Fix typo for trillion
Bug fix: remove ' from unformatting regex that was causing an error with fr-ch.js
Add zeroFormat() function that accepts a string for custom formating of zeros
Add valueOf() function
Chain functionality to language function
Make all minified files have the same .min.js filename ending
Bug fix: Bytes not formatting correctly
Add optional format for all decimals
Remove AMD module id. (This is encouraged by require.js to make the module more portable, and keep it from creating a global)
AMD define() compatibility.
Bug fix: Formatting some numbers results in the wrong value. Issue #21
Bug fix: Minor fix to unformatting parser
Add support for spaces before/after $, a, o, b in a format string
Bug fix: Fix unformat for languages that use '.' in ordinals
Bug fix: Fix round up floating numbers with no precision correctly.
Bug fix: Fix currency signs at the end in unformat
Add support for optional decimal places
Add support for appending currency symbol
Add support for humanized filesizes
Bug Fix: Fix unformatting for languages that use '.' as thousands delimiter
Changed language definition property 'money' to 'currency'
Bug fix: Fix unformatting non-negative abbreviations
Add language support
Update testing for to include languages
Add Tests
Bug fix: Fix difference returning negative values
Bug fix: Non negative numbers were displaying as negative when using parentheses
Add ordinal formatting using 'o' in the format
Add clone functionality
Added abbreviations for thousands and millions using 'a' in the format
Initial release
Numeral.js, while less complex, was inspired by and heavily borrowed from Moment.js
Numeral.js is freely distributable under the terms of the MIT license.
Copyright (c) 2012 Adam Draper
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.