如果是一千或以上的数字,将数字格式化为2.5K,否则为900。

319

我需要以 1K 的格式显示货币值,相当于一千,或者是 1.1K1.2K1.9K 等,如果不是整数千位数的话。否则,如果小于一千,则显示普通的数字如 500100250 等。请使用 JavaScript 格式化数字。


3
你是否还需要 MG - Salman A
我需要 M 个,你能帮忙吗? - Carl Weis
2
将JavaScript数字格式化为带有度量单位前缀的字符串(如1.5K、1M、1G等) - magritte
2
请参见 https://dev59.com/yWox5IYBdhLWcg3wDgPR#60988355,了解一个友好的ES2020本地化解决方案。 - Jay Wick
36个回答

422
更通用的版本:

function nFormatter(num, digits) {
  const lookup = [
    { value: 1, symbol: "" },
    { value: 1e3, symbol: "k" },
    { value: 1e6, symbol: "M" },
    { value: 1e9, symbol: "G" },
    { value: 1e12, symbol: "T" },
    { value: 1e15, symbol: "P" },
    { value: 1e18, symbol: "E" }
  ];
  const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
  var item = lookup.slice().reverse().find(function(item) {
    return num >= item.value;
  });
  return item ? (num / item.value).toFixed(digits).replace(rx, "$1") + item.symbol : "0";
}

/*
 * Tests
 */
const tests = [
  { num: 0, digits: 1 },
  { num: 12, digits: 1 },
  { num: 1234, digits: 1 },
  { num: 100000000, digits: 1 },
  { num: 299792458, digits: 1 },
  { num: 759878, digits: 1 },
  { num: 759878, digits: 0 },
  { num: 123, digits: 1 },
  { num: 123.456, digits: 1 },
  { num: 123.456, digits: 2 },
  { num: 123.456, digits: 4 }
];
tests.forEach(function(test) {
  console.log("nFormatter(" + test.num + ", " + test.digits + ") = " + nFormatter(test.num, test.digits));
});


1
@SalmanA - 非常感谢您的帮助,如果将参数作为字符串传递,它会失败,但是如果使用parseFloat进行清理,则可以正常工作。谢谢! - Adesh M
3
对于小于1000的数字进行微调,将{value: 1E0, symbol: ""}添加到变量si中。 - Dimmduh
3
@GiovanniAzua 只需将 if (num >= si[i].value) 替换为 if (Math.abs(num) >= si[i].value) - Salman A
1
@M.Octavio 正则表达式用于去除尾随零,例如 1.0 变成 11.10 变成 1.1 - Salman A
2
另外,在开始时处理特殊情况可能会更好。如果(num === 0),则返回0; - Raul
显示剩余11条评论

287

听起来这对您应该有效:

function kFormatter(num) {
    return Math.abs(num) > 999 ? Math.sign(num)*((Math.abs(num)/1000).toFixed(1)) + 'k' : Math.sign(num)*Math.abs(num)
}
    
console.log(kFormatter(1200)); // 1.2k
console.log(kFormatter(-1200)); // -1.2k
console.log(kFormatter(900)); // 900
console.log(kFormatter(-900)); // -900


7
建议进行小修复...应该使用小写 k 表示千。大写 K 是用来表示千克的。尝试编辑,但需要改变至少 6 个字符才能生效。 - Adam Youngers
我该如何在此处插入并使用php变量?例如,如果我的数字变量是$mynumber_output,我应该在哪里插入它以使用它?例如,假设$mynumber_output= 12846,我想将12846转换为12.8k - user7537274
请注意,在某些情况下,一千字节等于1024字节:https://zh.wikipedia.org/wiki/%E5%8D%83%E5%AD%97%E8%8A%82 - Olle Härstedt
6
没有完全回答用户的问题。“我需要M个……你能帮忙吗?”- Carl Weis - tim-montague
11
为了让 TypeScript 满意,建议使用 Math.round(Math.abs(num)/100)/10 替代 (Math.abs(num)/1000).toFixed(1)。这样不仅能够达到同样的计算结果,还更易于理解。 - Pierre de LESPINAY
显示剩余3条评论

252
ES2020在Intl.NumberFormat中增加了以下表示法的支持:

data-lang="js" data-hide="false" data-console="true" data-babel="false"

let formatter = Intl.NumberFormat('en', { notation: 'compact' });
// example 1
let million = formatter.format(1e6);
// example 2
let billion = formatter.format(1e9);
// print
console.log(million == '1M', billion == '1B');

请注意,如上所示,第二个示例输出1B而不是1GNumberFormat 规范:

请注意,目前并非所有浏览器都支持 ES2020,因此您可能需要使用此 Polyfill:https://formatjs.io/docs/polyfills/intl-numberformat


1
那个包已经被废弃,请使用这个链接: https://www.npmjs.com/package/@formatjs/intl-numberformat - Ammad Khalid
7
жіЁж„ЏпјљChromeж”ЇжЊЃnotationе’ЊcompactDisplayпјЊдЅ†FireFox 77е’ЊSafari 13.1д»ЌдёЌж”ЇжЊЃпјЊе› ж­¤ж‚ЁеЏЇиѓЅйњЂи¦ЃдЅїз”ЁpolyfillгЂ‚ - Josh Unger
1
哇,看来Firefox在版本78中刚刚添加了对此的支持。当然,2年后,这条评论看起来会很愚蠢。 :P(对我来说很有趣,因为代码可以运行但无法正确转换,所以我需要进行更新。) - Andrew
4
请注意,上述示例将12345格式化为12K而不是12.3K。您可以根据所需的行为添加maximumSignificantDigitsmaximumFractionDigits。例如,Intl.NumberFormat("en", { notation: "compact", maximumSignificantDigits: 3 }).format(12345) === "12.3K" 或者 Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(12345) === "12.3K" - Rik
3
注意上面的示例将 12345 格式化为 12K 而不是 12.3K。您可以添加 maximumSignificantDigitsmaximumFractionDigits,具体取决于您想要的行为。例如:Intl.NumberFormat("en", { notation: "compact", maximumSignificantDigits: 3 }).format(12345) === "12.3K" 或者 Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(12345) === "12.3K" - Rik
显示剩余3条评论

125

这里有一个简单的解决方案,它避免了所有的if语句(利用了Math的功能)。

var SI_SYMBOL = ["", "k", "M", "G", "T", "P", "E"];

function abbreviateNumber(number){

    // what tier? (determines SI symbol)
    var tier = Math.log10(Math.abs(number)) / 3 | 0;

    // if zero, we don't need a suffix
    if(tier == 0) return number;

    // get suffix and determine scale
    var suffix = SI_SYMBOL[tier];
    var scale = Math.pow(10, tier * 3);

    // scale the number
    var scaled = number / scale;

    // format number and add suffix
    return scaled.toFixed(1) + suffix;
}

彩蛋

SI 代表什么?


我真的很喜欢你的解决方案。为了能够缩短负值,我在确定层级之前和之后将数字乘以-1,因为Math.log10(negativeValue)会返回NaN。 - xhadon
3
只需要使用Math.abs来支持负数,像这样:var tier = Math.log10(Math.abs(number)) / 3 | 0; - Caio Tarifa
谢谢,我做出了改变以启用负数。 - Waylon Flinn
这个是否和被接受的答案一样,没有任何问题? - ThisDude
1
谢谢,这实际上是最易懂的答案,就发生了什么而言。 - Fabian
是的,这个更有意义,而且更容易阅读,特别是有注释。它也适用于负数,这是一个优点。 - train

95

进一步改进 Salman 的回答,因为它将 nFormatter(33000) 返回为 33.0K。

function nFormatter(num) {
     if (num >= 1000000000) {
        return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
     }
     if (num >= 1000000) {
        return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
     }
     if (num >= 1000) {
        return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
     }
     return num;
}

现在 nFormatter(33000) = 33K


3
有没有不四舍五入的方法来做这件事?1,590,000将返回1.6M。 - Brett Hardin
4
有时候很难确定是发表新答案还是编辑现有的答案,我通常用一个方法来决定:如果我从其他用户的答案中复制代码,我会编辑他们的答案,使得他们能够获得认可,而不是让我盗用他们的代码。 - M H
@Yash,你是我正在尝试在计数器脚本中实现的代码,但我无法理解。这是我的CodePen链接https://codepen.io/Merajkhan/pen/MMoxGE?editors=1010。你能帮我实现这个逻辑吗?我想要K、L、M单位出现。 - Mehraj Khan

54

简单直接的方法最易读,也使用最少的内存。不需要过度设计,比如使用正则表达式、map对象、Math对象、for循环等。

将货币值格式化为K

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3) return +(n / 1e3).toFixed(1) + "K";
};

console.log(formatCash(2500));

Formatting Cash value with K M B T

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(1) + "K";
  if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(1) + "M";
  if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(1) + "B";
  if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T";
};

console.log(formatCash(1235000));

Using negative numbers

let format;
const number = -1235000;

if (number < 0) {
  format = '-' + formatCash(-1 * number);
} else {
  format = formatCash(number);
}

1
@Jan - 我更新了我的帖子,并提供了一个例子,但我觉得使用 '-' + formatCash(-1 * number) 计算负数形式非常简单。 - tim-montague

29
/**
 * Shorten number to thousands, millions, billions, etc.
 * http://en.wikipedia.org/wiki/Metric_prefix
 *
 * @param {number} num Number to shorten.
 * @param {number} [digits=0] The number of digits to appear after the decimal point.
 * @returns {string|number}
 *
 * @example
 * // returns '12.5k'
 * shortenLargeNumber(12543, 1)
 *
 * @example
 * // returns '-13k'
 * shortenLargeNumber(-12567)
 *
 * @example
 * // returns '51M'
 * shortenLargeNumber(51000000)
 *
 * @example
 * // returns 651
 * shortenLargeNumber(651)
 *
 * @example
 * // returns 0.12345
 * shortenLargeNumber(0.12345)
 */
function shortenLargeNumber(num, digits) {
    var units = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
        decimal;

    for(var i=units.length-1; i>=0; i--) {
        decimal = Math.pow(1000, i+1);

        if(num <= -decimal || num >= decimal) {
            return +(num / decimal).toFixed(digits) + units[i];
        }
    }

    return num;
}

感谢@Cos的评论,我已删除Math.round10依赖。


1
你可以将if改为Math.abs(num) >= decimal - Conor Pender

23

如果您喜欢这篇文章,请为Waylon Flinn点赞

本文在Waylon Flinn更加优雅地处理负数和".0"情况的基础上进行改进。

在我看来,循环和“if”语句越少越好。

function abbreviateNumber(number) {
    const SI_POSTFIXES = ["", "k", "M", "G", "T", "P", "E"];
    const sign = number < 0 ? '-1' : '';
    const absNumber = Math.abs(number);
    const tier = Math.log10(absNumber) / 3 | 0;
    // if zero, we don't need a prefix
    if(tier == 0) return `${absNumber}`;
    // get postfix and determine scale
    const postfix = SI_POSTFIXES[tier];
    const scale = Math.pow(10, tier * 3);
    // scale the number
    const scaled = absNumber / scale;
    const floored = Math.floor(scaled * 10) / 10;
    // format number and add postfix as suffix
    let str = floored.toFixed(1);
    // remove '.0' case
    str = (/\.0$/.test(str)) ? str.substr(0, str.length - 2) : str;
    return `${sign}${str}${postfix}`;
}

带有测试用例的jsFiddle -> https://jsfiddle.net/qhbrz04o/9/


1
仍然存在一个烦人的 bug:abbreviateNumber(999999) == '1000k' 而不是 '1M'。这是因为 toFixed() 也会四舍五入数字。不过我不确定该如何修复它 :/ - Vitor Baptista
@VitorBaptista 如果 toFixed() 无论如何都会四舍五入,那么在将数字发送到 abbreviateNumber() 之前就将其四舍五入,这样它返回的就是 1M 而不是 1000k。虽然不是解决方案,但可以作为一种变通方法。 - forsureitsme
2
如果您不想进行四舍五入,可以在缩放步骤之后执行以下操作:const floored = Math.floor(scaled * 10) / 10; - tybro0103
1
无法正确处理负数。 - doğukan
1
@forsureitsme 抱歉我一年没看到这个了... 我已经添加了你的更改。谢谢! - King Friday

16

这很优雅。

function formatToUnits(number, precision) {
  const abbrev = ['', 'k', 'm', 'b', 't'];
  const unrangifiedOrder = Math.floor(Math.log10(Math.abs(number)) / 3)
  const order = Math.max(0, Math.min(unrangifiedOrder, abbrev.length -1 ))
  const suffix = abbrev[order];

  return (number / Math.pow(10, order * 3)).toFixed(precision) + suffix;
}

formatToUnits(12345, 2)
==> "12.35k"
formatToUnits(0, 3)
==> "0.000"

16

我认为这可以是一个解决方案。

var unitlist = ["","K","M","G"];
function formatnumber(number){
   let sign = Math.sign(number);
   let unit = 0;
   
   while(Math.abs(number) >= 1000)
   {
     unit = unit + 1; 
     number = Math.floor(Math.abs(number) / 100)/10;
   }
   console.log(sign*Math.abs(number) + unitlist[unit]);
}
formatnumber(999);
formatnumber(1234);
formatnumber(12345);
formatnumber(123456);
formatnumber(1234567);
formatnumber(12345678);
formatnumber(1000);
formatnumber(-999);
formatnumber(-1234);
formatnumber(-12345);
formatnumber(-123456);
formatnumber(-1234567);
formatnumber(-12345678);


谢谢,这很有帮助,因为它不像其他数字一样是一个圆形的返回值。 - Sandeep Sherpur
1
这个函数使用了大量的资源,因为它一遍又一遍地迭代相同的数字。我的 Web 应用在 Chrome 和 Safari 中冻结了,原因是我多次使用了这个函数。 - Victor
我认为这与此函数无关。 我进行了10万次调用的测试,没有发生任何事情。 请分享你的代码。 - BTSM
对于数字"1000",返回的结果是"1000"。要返回"1K",请将while行中的"> 1000"替换为">= 1000"。 - NathanPB
对于数字"1000",这将返回"1000"。要返回"1K",请在while行中将"> 1000"替换为">= 1000"。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接