如何显示或隐藏负数的负号?

在不同场景下,灵活控制格式化数字的正负号显示

简介

不同的场景对负数的表示有不同需求。例如,显示温度变化的仪表盘需要明确的正负号来指示变化方向;只关注绝对值的图表则应完全隐藏符号;财务报表则遵循会计规范,用括号包裹负数金额而不是使用负号。

JavaScript 的 Intl.NumberFormat API 提供 signDisplay 选项,用于控制格式化数字时符号的显示时机。该选项可让你精确控制负数、正数和零的符号可见性。

JavaScript 默认如何格式化负数

默认情况下,Intl.NumberFormat 会为负数显示负号,正数则不显示符号。

const formatter = new Intl.NumberFormat('en-US');

formatter.format(-42);
// "-42"

formatter.format(42);
// "42"

formatter.format(0);
// "0"

这种默认行为适用于大多数场景,但如果你的需求不同,也可以自定义符号的显示方式。

使用 signDisplay 选项控制符号显示

signDisplay 选项接受五个值,用于控制符号的显示时机:

  • "auto":仅为负数(包括负零)显示符号(默认)
  • "never":从不显示符号
  • "always":始终为正数和负数都显示符号
  • "exceptZero":仅为正数和负数显示符号,零不显示
  • "negative":仅为负数显示符号,不包括负零

在创建格式化器时,将 signDisplay 选项传递到 options 对象中。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'always'
});

完全隐藏负号

使用 signDisplay: 'never' 可以隐藏所有符号,仅显示绝对值。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'never'
});

formatter.format(-100);
// "100"

formatter.format(100);
// "100"

formatter.format(-0);
// "0"

此设置会去除所有数字的符号,使 -100100 的格式化结果相同。负零会以 "0" 形式显示,不带符号。

当只需展示数值大小、方向无关时(如数据可视化中的绝对变化值、距离计算或误差范围),请使用此选项。

const changes = [-15, 23, -8, 42];

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'never'
});

changes.map(change => formatter.format(change));
// ["15", "23", "8", "42"]

仅对负数显示负号

signDisplay: 'auto' 选项是默认行为。它只为负数显示符号,正数不显示。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'auto'
});

formatter.format(-100);
// "-100"

formatter.format(100);
// "100"

formatter.format(-0);
// "-0"

请注意,使用此选项时,负零会显示为 "-0"。JavaScript 区分正零和负零,这种情况可能出现在某些数学运算中。

使用 signDisplay: 'negative' 可以隐藏负零的符号,但保留其他负数的符号。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'negative'
});

formatter.format(-100);
// "-100"

formatter.format(100);
// "100"

formatter.format(-0);
// "0"

negative 选项将负零视为特殊情况,并以无符号格式显示。这样可以避免在用户无需区分正零和负零的场景下出现令人困惑的显示。

除零以外的所有数字都显示符号

使用 signDisplay: 'exceptZero' 可为正数和负数都显示符号,但当数值为零时省略符号。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'exceptZero'
});

formatter.format(-100);
// "-100"

formatter.format(100);
// "+100"

formatter.format(0);
// "0"

formatter.format(-0);
// "0"

正数会显示加号。无论是正零还是负零,零值都不会显示任何符号。

此选项适用于展示变化量或增量,零表示无变化。显示 "+0""-0" 会让人困惑,而显示 "0" 则能清晰表达含义。

const deltas = [5, -3, 0, -0, 12];

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'exceptZero'
});

deltas.map(delta => formatter.format(delta));
// ["+5", "-3", "0", "0", "+12"]

所有数字都显示符号

使用 signDisplay: 'always' 可为所有数字显示符号,包括正数和零。

const formatter = new Intl.NumberFormat('en-US', {
  signDisplay: 'always'
});

formatter.format(-100);
// "-100"

formatter.format(100);
// "+100"

formatter.format(0);
// "+0"

formatter.format(-0);
// "-0"

此设置会为正数和正零添加加号。负零则保留负号,从而使区分更加直观。

当你需要对所有数值的方向性进行强调时(如温度变化、高度变化或财务盈亏),请使用此选项。

const temperatures = [-5, 0, 3, -2];

const formatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'celsius',
  signDisplay: 'always'
});

temperatures.map(temp => formatter.format(temp));
// ["-5°C", "+0°C", "+3°C", "-2°C"]

结合符号显示与货币格式化

signDisplay 选项适用于所有格式化样式,包括货币格式。与 currencySign: 'accounting' 结合时,可以创建符合会计规范的格式。

const formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencySign: 'accounting'
});

formatter.format(-1234.56);
// "($1,234.56)"

会计记法会用括号括起负数金额,而不是使用负号。这种规范让财务报表中的负数更加醒目。

你可以将会计记账法与不同的 signDisplay 值结合使用。

const always = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencySign: 'accounting',
  signDisplay: 'always'
});

always.format(1234.56);
// "+$1,234.56"

always.format(-1234.56);
// "($1,234.56)"

const never = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencySign: 'accounting',
  signDisplay: 'never'
});

never.format(-1234.56);
// "$1,234.56"

使用 signDisplay: 'always' 时,正数会显示加号,负数仍用括号表示。使用 signDisplay: 'never' 时,正负数都不显示符号或括号。

何时使用每种符号显示选项

请根据你的数字所代表的含义以及用户的解读方式选择合适的 signDisplay 值。

如需标准数字格式且需明确区分负数,请使用 signDisplay: 'auto'。这是默认选项,适用于价格、计数、测量和大多数通用数字显示。

当展示绝对值或只需数值大小、方向无关时,使用 signDisplay: 'never'。适用于距离计算、误差范围、绝对变化值和仅需展示数值大小的数据可视化。

当你需要标准负数格式化但又要避免显示负零时,请使用 signDisplay: 'negative'。这样可以防止在数学或科学场景下出现 "-0" 这种让用户困惑的显示,因为在这些场景下正零和负零的区分对用户来说并不重要。

在展示变化值或增减(delta)时,如果零表示无变化,建议使用 signDisplay: 'exceptZero'。这样可以清晰区分增益和损失,同时避免 "+0""-0" 的混淆显示。温度变化、股票价格波动和性能指标等场景都适合使用此选项。

当所有数值的方向性都很重要,并且你希望同时强调增减变化时,请使用 signDisplay: 'always'。温度变化、高差、财务业绩报告等通常采用这种格式,以便正负值都能被明确表达。

// Standard pricing: use auto (default)
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(-50);
// "-$50.00"

// Absolute price difference: use never
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  signDisplay: 'never'
}).format(-50);
// "$50.00"

// Price change: use exceptZero
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  signDisplay: 'exceptZero'
}).format(50);
// "+$50.00"

// Temperature change: use always
new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'celsius',
  signDisplay: 'always'
}).format(3);
// "+3°C"

signDisplay 选项可让你精确控制应用中正数和负数的显示方式。请根据每个数字的上下文和用途,选择最能向用户传达含义的显示方式。