冷门的toLocaleString

js 里面除了我们日常使用的api以外, 其实还是有不少大多数人都不知道的很好用的api的, toLocaleString算一个, 也许你在面试题中看到过用正则来实现数字千位用逗号分隔的做法, 但是如果你能直接说出toLocaleString, 应该是出乎面试官的意料的, 而它的用法可不止于此.

toLocaleString方法在NumnberDate类型上都有部署, 实现的作用都是格式化数字或者日期, 返回格式化后的字符串.

# Number.prototype.toLocaleString

api: toLocaleString([locales [, options]])

locales指定地区, 默认是按照当前电脑环境的语言, 也可以指定不同的语言, 中文是zh, 英文是en, 其它可选项请查看MDN, 不区分大小写.

例如:

const a = -2345679.56789;
const b = new Date();

// 单纯的数字的格式化在 zh 和 en 是相同的
a.toLocalString(); // => "-2,345,679.568"
a.toLocaleString('zh'); // => "-2,345,679.568"
a.toLocaleString('en'); // => "-2,345,679.568"

// 日期的格式化就能看出语言差异了
b.toLocalString(); // => "2019/4/25 上午10:27:15"
b.toLocaleString('zh'); // => "2019/4/25 上午10:27:15"
b.toLocaleString('en'); // => "4/25/2019, 10:27:15 AM"

options参数才是重头戏, 它可以定义更多的配置项, 但是一定要先指定locales参数, 才能使用options参数.

options对象中的style表示格式化时使用的格式, 默认是decimal即纯数字, 另外还有percent百分比和currency货币形式, 需要注意的是如果指定stylecurrency, 那么必须接着指定currency属性才行, 因为currency没有默认值, 可选值有CNY人民币, USD美元, EUR欧元等, 更多请参考MDN

指定了stylecurrency之后, 除了currency属性之外, 还有一个currencyDisplay属性可用, 默认值是symbol即货币符号, 另外两个可选值为code代码(如CNY)和name名称(如人民币)

const c = 80909.89;
c.toLocaleString('zh', {style: 'percent'}); // => "8,090,989%"
c.toLocaleString('zh', {style: 'currency', currency: 'CNY'}); // => "¥80,909.89"
c.toLocaleString('zh', {style: 'currency', currency: 'CNY', currencyDisplay: 'name'}); // => "80,909.89 人民币"

接下来是options里面的两组不能同时使用的参数, 一组是minimumIntegerDigits, minimumFractionDigitsmaximumFractionDigits, 另一组是minimumSignificantDigitsmaximumSignificantDigits

前一组是用来指定数字的最少整数位数, 最少小数位数和最多小数位数, 后一组用来指定最少数字位数和最多数字位数(包括整数和小数一起). 如果指定了后一组参数, 那么前一组参数就会被忽略掉. 指定位数的规则都是按照四舍五入, 是真正的数学上的四舍五入, 而不是像toFixed那样的按照银行家算法的伪四舍五入, 如果位数不足的话就会自动用0补齐. 四舍五入, 自动补齐, 想想就知道有多大潜力!

另外style里面还有一个useGrouping参数, 表示是否使用分组分隔符,如千位分隔符或千/万/亿分隔符, 默认为true

const d = 892839.855;

d.toLocaleString('zh', { style: 'currency', currency: 'CNY' ,minimumFractionDigits: 2, maximumFractionDigits:2 }); // => "¥892,839.86"
d.toLocaleString('zh', { style: 'currency', currency: 'CNY' ,minimumFractionDigits: 2, maximumFractionDigits:2, useGrouping: false }); // => "¥892839.86"

看看上面的金额格式化的示例, 只需要一行语句多简洁啊, 我之前还专门写了个函数来做金额的格式化显示, 跟这个一比差远了...

/**
 * @description: format money to standard string including prefix, separator and two decimal places
 * @param {number | string} currency
 * @param {string} prefix prefix the output with the specified string
 * @return: {string} formated currency
 */
function formatCurrency(currency = '', prefix = '') {
  const split = currency.toString().split('.');
  let integer = split[0] || '0';
  if (integer.startsWith('¥')) {
    integer = integer.slice(1, integer.length);
  }
  let isNegative = false;
  if(integer.startsWith('-')) {
    isNegative = true;
    integer = integer.slice(1, integer.length);
  }
  let decimal = split[1] || '00';
  let output = '';
  while (integer.length > 3) {
    output = `,${integer.slice(-3)}${output}`;
    integer = integer.slice(0, integer.length - 3);
  }
  if (integer) {
    output = integer + output;
  }
  if (decimal.length < 2) {
    decimal = decimal + '0';
  }
  output = `${isNegative ? '-' : ''}${prefix}${output}.${decimal}`;
  return output;
}

# Date.prototype.toLocaleString

api: toLocaleString([locales [, options]])

locales参数与之前的一致, 也是指定语言, 默认是当前电脑环境语言

options参数就不一样了, 里面的hour12表示使用十二小时制还是二十四小时制, 默认值根据当前环境变化而变化

const e = new Date();

e.toLocaleString('zh', {hour12: true}); // => "2019/4/25 下午11:07:32"
e.toLocaleString('zh', {hour12: false}); // => "2019/4/25 23:07:32"

然后是对年月日星期时分秒时区等的显示格式设置, 参数分别是year, month, day, weekday, hour, minute, second, timeZoneName.

weekday可选值为narrow, shortlong, 就是缩写的长度不同, 例如 Wednesday 依次显示为 W , Wed 和 Wednesday timeZoneName可选值为shortlong, 例如 GMT+8 和 中国标准时间 其余的参数可选值为numeric2-digit, 区别是numeric直接显示, 2-digit会固定显示两位数, 例如 7 和 07 month除了numeric2-digit外还有narrow, shortlong, 额外的这三个其实也是控制缩写的长度(设置localesen能看出差别)

# 参考文章

Number​.prototype​.toLocale​String() toLocaleString 了解一下