你不知道的一些数字使用方法

358 阅读6分钟

数字类型

编写数字的方法

表示十个亿很显然我们可以写成

let billion = 1000000000;

当然加上下划线作为分隔符也可以方便我们的阅读;JavaScript 引擎会直接忽略数字之间的 _

let billion = 1_000_000_000;

不过我们是懒的,在 JavaScript 中,我们可以通过在数字后面附加字母 "e" 并指定零的个数来缩短数字:

let billion = 1e9; // 10 亿,字面意思:数字 1 后面跟 9 个 0
alert( 7.3e9 ); // 73 亿(与 7300000000 和 7_300_000_000 相同)

同样我们可以用附加字母 "e" 写一个很小的数字let mcs = 1e-6; 表示 1 的左边有 6 个 0

Number.prototype.toString()

语法:numObj.toString([radix])

radix: 指定要用于数字到字符串的转换的基数 (从 2 到 36)。如果未指定 radix 参数,则默认值为 10。

如果转换的基数大于 10,则会使用字母来表示大于 9 的数字,比如基数为 16 的情况,则使用 a 到 f 的字母来表示 10 到 15。

如果基数没有指定,则使用 10。

如果对象是负数,则会保留负号。即使 radix 是 2 时也是如此:返回的字符串包含一个负号(-)前缀和正数的二进制表示,不是 数值的二进制补码。

进行数字到字符串的转换时,建议用小括号将要转换的目标括起来,防止出错。

🐱‍👓示例:

 console.log((254).toString(16)); //fe
 console.log((259).toString(16)); //103 
 console.log((254).toString(2));//11111110

“fe”的原因是16进制,e代表14 ,f是15,15*16=240 再加上14 结果为254

“11111110”是使用二进制的结果

那么试试36进制吧~

console.log( 123456..toString(36) ); // 2n9c

👀使用两个点来调用一个方法:

请注意 123456..toString(36) 中的两个点不是打错了。如果我们想直接在一个数字上调用一个方法,比如上面例子中的 toString,那么我们需要在它后面放置两个点 ..。 如果我们放置一个点:123456.toString(36),那么就会出现一个 error,因为 JavaScript 语法隐含了第一个点之后的部分为小数部分。如果我们再放一个点,那么 JavaScript 就知道小数部分为空,现在使用该方法。 也可以写成 (123456).toString(36)

舍入

舍入(rounding)是使用数字时最常用的操作之一。

这里有几个对数字进行舍入的内建函数:

Math.floor

向下舍入:`3.1` 变成 `3``-1.1` 变成 `-2`

Math.ceil

向上舍入:`3.1` 变成 `4``-1.1` 变成 `-1`

Math.round

向最近的整数舍入:`3.1` 变成 `3``3.6` 变成 `4`,中间值 `3.5` 变成 `4`

Math.trunc(IE 浏览器不支持这个方法)

移除小数点后的所有内容而没有舍入:`3.1` 变成 `3``-1.1` 变成 `-1`

但是如果我们有个需求是想要舍入到小数点后两位怎么办?

乘除法

先让他乘100而后除回

let num = 1.23456; 
alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23

函数toFixed(n)

函数toFixed(n)将数字舍入到小数点后 n 位,并以字符串形式返回结果。

console.log((12.315).toFixed(1)); // "12.3"

详细点:

var numObj = 12345.6789;

numObj.toFixed();         // 返回 "12346":进行四舍六入五看情况,不包括小数部分
numObj.toFixed(1);        // 返回 "12345.7":进行四舍六入五看情况

numObj.toFixed(6);        // 返回 "12345.678900":用 0 填充

(1.23e+20).toFixed(2);    // 返回 "123000000000000000000.00"

(1.23e-10).toFixed(2);    // 返回 "0.00"

2.34.toFixed(1);          // 返回 "2.3"

2.35.toFixed(1)           // 返回 '2.4'. Note it rounds up

2.55.toFixed(1)           // 返回 '2.5'. Note it rounds down - see warning above

-2.34.toFixed(1);         // 返回 -2.3(由于操作符优先级,负数不会返回字符串)

(-2.34).toFixed(1);       // 返回 "-2.3"(若用括号提高优先级,则返回字符串)

由于操作符优先级,负数不会返回字符串;若用括号提高优先级,则返回字符串

parseInt 和 parseFloat

使用加号 + 或 Number() 的数字转换是严格的。如果一个值不完全是一个数字,就会失败:

alert( +"100px" ); // NaN

唯一的例外是字符串开头或结尾的空格,因为它们会被忽略。

但在现实生活中,我们经常会有带有单位的值,例如 CSS 中的 "100px" 或 "12pt"。并且,在很多国家,货币符号是紧随金额之后的,所以我们有 "19€",并希望从中提取出一个数值。

这就是 parseInt 和 parseFloat 的作用。

它们可以从字符串中“读取”数字,直到无法读取为止。如果发生 error,则返回收集到的数字。函数 parseInt 返回一个整数,而 parseFloat 返回一个浮点数:

alert( parseInt('100px') ); // 100 
alert( parseFloat('12.5em') ); // 12.5 
alert( parseInt('12.3') ); // 12,只有整数部分被返回了 
alert( parseFloat('12.3.4') ); // 12.3,在第二个点出停止了读取
alert( parseInt('a123') ); // NaN,第一个符号停止了读取

第一个符号停止了读取后,parseInt/parseFloat 会返回 NaN

parseInt(str, radix) 的第二个参数

parseInt() 函数具有可选的第二个参数。它指定了数字系统的基数,因此 parseInt 还可以解析十六进制数字、二进制数字等的字符串:

alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255,没有 0x 仍然有效
alert( parseInt('2n9c', 36) ); // 123456

警告:parseInt 将 BigInt 转换为 Number,并在这个过程中失去了精度。这是因为拖尾的非数字值,包括 "n",会被丢弃。

注意

在内部,数字是以 64 位格式 IEEE-754 表示的,所以正好有 64 位可以存储一个数字:其中 52 位被用于存储这些数字,其中 11 位用于存储小数点的位置,而 1 位用于符号。

如果一个数字真的很大,则可能会溢出 64 位存储,变成一个特殊的数值 Infinity就会导致精度的损失

浮点数(float)不能精确地用二进制表示所有小数。这可能会导致意外的结果,例如 0.1 + 0.2 === 0.3 返回 fals

什么是 0.10.1 就是 1 除以 101/10,即十分之一。在十进制数字系统中,这样的数字表示起来很容易。将其与三分之一进行比较:1/3。三分之一变成了无限循环小数 0.33333(3)

在十进制数字系统中,可以保证以 10 的整数次幂作为除数能够正常工作,但是以 3 作为除数则不能。也是同样的原因,在二进制数字系统中,可以保证以 2 的整数次幂作为除数时能够正常工作,但 1/10 就变成了一个无限循环的二进制小数。

使用二进制数字系统无法 精确 存储 0.1 或 0.2,就像没有办法将三分之一存储为十进制小数一样。

解决办法: 最可靠的方法是借助方法toFixed(n)对结果进行舍入,注意乘/除法可以减少误差,但不能完全消除误差。