如何控制货币格式中的正负号

使用 signDisplay 选项在 JavaScript 中格式化货币金额时显示或隐藏正负号

简介

当您在银行应用中显示类似 $500 的交易金额时,用户无法判断这是存款还是取款。缺少正号或负号会导致歧义。通过显示 +$500 或 -$500,您可以清楚地传达交易方向。

金融应用需要对货币金额的符号显示进行精确控制。交易历史需要通过明确的符号显示存款和取款。损益表需要通过清晰的正负指标显示收益和损失。账户余额变动需要可见的符号来表明资金是进入还是流出账户。JavaScript 的 Intl.NumberFormat 提供了 signDisplay 选项,可以精确控制格式化货币时正负符号的显示。

默认货币格式

默认情况下,Intl.NumberFormat 对于负的货币金额显示负号,而对于正的金额则不显示符号。

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

console.log(formatter.format(250.50));
// 输出:"$250.50"

console.log(formatter.format(-75.25));
// 输出:"-$75.25"

console.log(formatter.format(0));
// 输出:"$0.00"

这种默认行为适合显示价格和账户余额。然而,当显示交易金额或财务变动时,正值缺少正号会使方向不明确。

使用 signDisplay 控制货币符号

signDisplay 选项控制格式化货币时正负符号的显示。创建货币的数字格式化器时可以传递此选项。

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

console.log(formatter.format(250.50));
// 输出:"+$250.50"

console.log(formatter.format(-75.25));
// 输出:"-$75.25"

现在正值金额会显示正号,使存款和收益明确而非隐含。

了解货币的 signDisplay 值

signDisplay 选项接受五种值。每种值在财务显示中都有特定用途。

auto 值用于标准货币格式化

"auto" 值是默认行为。它会对负数显示减号,但对正数不显示符号。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "auto"
});

console.log(formatter.format(1000));
// 输出: "$1,000.00"

console.log(formatter.format(-500));
// 输出: "-$500.00"

console.log(formatter.format(0));
// 输出: "$0.00"

使用 "auto" 来显示价格、账户余额以及其他需要标识负数但默认正数的绝对货币值。

always 值显示所有交易方向

"always" 值会对所有金额显示符号,包括正数、负数和零。

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

console.log(formatter.format(1000));
// 输出: "+$1,000.00"

console.log(formatter.format(-500));
// 输出: "-$500.00"

console.log(formatter.format(0));
// 输出: "+$0.00"

使用 "always" 用于交易历史、损益表和账户活动记录,在每个条目中明确资金流动方向。显式的加号表明正数代表存款、收益或入账资金。

exceptZero 值突出实际变化

"exceptZero" 值会对正数和负数显示符号,但对零不显示符号。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "exceptZero"
});

console.log(formatter.format(1000));
// 输出: "+$1,000.00"

console.log(formatter.format(-500));
// 输出: "-$500.00"

console.log(formatter.format(0));
// 输出: "$0.00"

使用 "exceptZero" 来显示余额变化,其中零表示没有变化。这使零在视觉上与实际的收益或损失区分开来。交易平台和投资应用使用此格式来显示价格变化和投资组合价值变化。

使用负值强调债务

"negative" 值仅对负数金额显示负号,不包括负零。正数和零则不显示符号。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "negative"
});

console.log(formatter.format(1000));
// 输出: "$1,000.00"

console.log(formatter.format(-500));
// 输出: "-$500.00"

console.log(formatter.format(0));
// 输出: "$0.00"

使用 "negative" 适用于账户余额,其中负数金额表示需要强调的债务或透支。正数余额被视为正常,而负数余额则引起注意。

使用 never 值显示绝对金额

"never" 值在显示货币金额时不显示任何符号,即使是负值。

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

console.log(formatter.format(1000));
// 输出: "$1,000.00"

console.log(formatter.format(-500));
// 输出: "$500.00"

console.log(formatter.format(0));
// 输出: "$0.00"

使用 "never" 适用于显示绝对金额的场景,其中方向通过其他方式传达。例如,交易列表使用单独的列表示借方和贷方,或者通过颜色编码区分正负值,去掉符号可以避免冗余信息。

将 signDisplay 与会计风格结合使用

货币格式支持一种会计符号表示法,将负数金额显示在括号中。将 currencySign 设置为 "accounting" 以启用此格式。

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

console.log(formatter.format(1000));
// 输出: "$1,000.00"

console.log(formatter.format(-500));
// 输出: "($500.00)"

会计格式使用括号包裹负数金额,而不是使用负号。这种惯例常见于财务报告、会计软件和商业报表中。

您可以将会计符号与不同的 signDisplay 值结合使用,以控制正数金额的显示方式,同时负数金额使用括号。

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

console.log(formatter.format(1000));
// 输出: "+$1,000.00"

console.log(formatter.format(-500));
// 输出: "($500.00)"

console.log(formatter.format(0));
// 输出: "+$0.00"

使用 signDisplay: "always" 时,正数金额显示加号,而负数金额继续使用括号。这种格式适用于需要明确区分收益和损失的损益表。

使用 signDisplay: "exceptZero" 时,零不显示符号,而正数和负数金额使用各自的指示符号。

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

console.log(formatter.format(1000));
// 输出: "+$1,000.00"

console.log(formatter.format(-500));
// 输出: "($500.00)"

console.log(formatter.format(0));
// 输出: "$0.00"

这种组合方式在突出实际变化的同时,使零的显示保持中性。

signDisplay 如何与货币显示模式配合工作

货币格式化支持三种货币显示模式。通过 currencyDisplay 选项可以控制货币是以符号、代码还是名称的形式显示。

signDisplay 选项在所有货币显示模式下都能保持一致的工作方式。

const symbol = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "symbol",
  signDisplay: "always"
});

console.log(symbol.format(100));
// 输出:"+$100.00"

const code = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "code",
  signDisplay: "always"
});

console.log(code.format(100));
// 输出:"+USD 100.00"

const name = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "name",
  signDisplay: "always"
});

console.log(name.format(100));
// 输出:"+100.00 US dollars"

无论货币如何显示,符号都会出现在适当的位置。这确保了在不同的货币格式中符号的可见性一致。

符号位置因地区而异

不同的地区会根据货币符号的位置采用不同的符号位置。JavaScript 会自动处理这些特定于地区的约定。

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

console.log(enUS.format(100));
// 输出:"+$100.00"

console.log(enUS.format(-100));
// 输出:"-$100.00"

const frFR = new Intl.NumberFormat("fr-FR", {
  style: "currency",
  currency: "EUR",
  signDisplay: "always"
});

console.log(frFR.format(100));
// 输出:"+100,00 €"

console.log(frFR.format(-100));
// 输出:"-100,00 €"

在美式英语中,符号出现在货币符号之前。在法语中,符号出现在数字之前,而货币符号在数字之后。格式化器会遵循这些地区约定,同时尊重您的 signDisplay 选择。

即使使用 signDisplay: "always",某些地区的负号位置也可能与正号位置不同。

const nlNL = new Intl.NumberFormat("nl-NL", {
  style: "currency",
  currency: "EUR",
  signDisplay: "always"
});

console.log(nlNL.format(100));
// 输出:"+€ 100,00"

console.log(nlNL.format(-100));
// 输出:"-€ 100,00"

JavaScript 确保输出遵循每个地区的正确格式规则,同时保持您指定的符号可见性。

货币符号控制的实际用例

不同的金融场景需要不同的符号显示策略。

交易历史

银行应用和支付平台会显示交易列表,其中每一项都展示资金的流入或流出。使用 signDisplay: "always" 来明确每笔交易的方向。

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

const transactions = [
  { description: "Salary deposit", amount: 3500 },
  { description: "Rent payment", amount: -1200 },
  { description: "Grocery store", amount: -85.50 },
  { description: "Refund", amount: 25 }
];

transactions.forEach(transaction => {
  console.log(`${transaction.description}: ${formatter.format(transaction.amount)}`);
});
// 输出:
// Salary deposit: +$3,500.00
// Rent payment: -$1,200.00
// Grocery store: -$85.50
// Refund: +$25.00

明确的符号可以清楚地表明每笔交易是增加还是减少了账户余额。

损益表

财务报告通过清晰的正负指标显示收益和损失。使用 signDisplay: "always" 和会计符号格式来生成专业的财务报表。

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

const financials = {
  revenue: 150000,
  expenses: -95000,
  netIncome: 55000
};

console.log(`Revenue: ${formatter.format(financials.revenue)}`);
// 输出: Revenue: +$150,000.00

console.log(`Expenses: ${formatter.format(financials.expenses)}`);
// 输出: Expenses: ($95,000.00)

console.log(`Net Income: ${formatter.format(financials.netIncome)}`);
// 输出: Net Income: +$55,000.00

这种格式遵循会计惯例,同时清晰地显示了收益和损失。

余额变动指示器

投资平台和交易应用会显示账户价值随时间的变化。使用 signDisplay: "exceptZero" 来突出实际变化,同时让无变化的情况显得中性。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "exceptZero"
});

const changes = [
  { period: "Today", change: 125.50 },
  { period: "This week", change: -45.75 },
  { period: "This month", change: 0 },
  { period: "This year", change: 1850 }
];

changes.forEach(item => {
  console.log(`${item.period}: ${formatter.format(item.change)}`);
});
// 输出:
// Today: +$125.50
// This week: -$45.75
// This month: $0.00
// This year: +$1,850.00

零值不显示符号,突出了该期间没有变化的情况。

账户余额

银行应用程序显示当前账户余额,其中负值表示透支。使用 signDisplay: "negative" 来突出显示债务,同时将正余额视为正常。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "negative"
});

const accounts = [
  { name: "Checking", balance: 2500 },
  { name: "Savings", balance: 15000 },
  { name: "Credit Card", balance: -850 }
];

accounts.forEach(account => {
  console.log(`${account.name}: ${formatter.format(account.balance)}`);
});
// 输出:
// Checking: $2,500.00
// Savings: $15,000.00
// Credit Card: -$850.00

负号引起对负余额的注意,而正余额则不显示符号。

价格比较的绝对差异

购物应用程序和价格比较工具显示选项之间的价格差异。显示绝对价格差异时,使用 signDisplay: "never",因为方向无关紧要。

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

const comparisons = [
  { item: "Laptop A vs B", difference: -150 },
  { item: "Phone X vs Y", difference: 75 },
  { item: "Tablet M vs N", difference: -25 }
];

comparisons.forEach(comp => {
  console.log(`${comp.item}: ${formatter.format(comp.difference)} difference`);
});
// 输出:
// Laptop A vs B: $150.00 difference
// Phone X vs Y: $75.00 difference
// Tablet M vs N: $25.00 difference

所有金额都显示为正值,表示差异的大小,而不考虑哪个选项更贵。

将 signDisplay 与小数精度结合使用

signDisplay 选项可与所有其他货币格式化选项一起使用。您可以同时控制小数位数、舍入和符号显示。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(formatter.format(1234.5));
// 输出: "+$1,234.50"

console.log(formatter.format(-89.1));
// 输出: "-$89.10"

这确保了小数精度的一致性,同时为所有金额显示明确的符号。

您还可以将 signDisplay 与最小和最大有效数字结合使用,用于科学或财务计算。

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always",
  minimumSignificantDigits: 3,
  maximumSignificantDigits: 3
});

console.log(formatter.format(1234.567));
// 输出: "+$1,230"

console.log(formatter.format(-0.0456));
// 输出: "-$0.0456"

格式化器在应用有效数字规则的同时,保持您指定的符号显示行为。

需要记住的事项

Intl.NumberFormat 中的 signDisplay 选项控制格式化货币金额时正负号的显示方式。使用 "always" 可对所有金额显示明确的符号,使用 "exceptZero" 可对零隐藏符号,使用 "auto" 表示默认行为,使用 "negative" 仅显示负号,使用 "never" 隐藏所有符号。

根据您的财务上下文选择合适的 signDisplay 值。交易历史需要对所有金额显示明确的符号。余额变动指示器可以通过使零值视觉上中性来获益。账户余额适合仅突出显示负值。价格比较通常需要不带符号的绝对值。

signDisplay 与会计符号、货币显示模式和小数精度选项结合使用,以创建适合您的金融应用程序的精确货币格式。JavaScript 会自动处理特定于区域的符号位置,同时尊重您的符号显示偏好。