🔢 JavaScript 数字类型
在 JavaScript 中,数字类型中两种:
- 常规数字以 64 位的格式 IEEE-754 (opens new window) 存储,也被称为「双精度浮点数」,安全范围在:-253 ~ 253 。常用的数字以这种为主。
- BigInt 数字,用于表示任意长度的整数。仅在少数特殊领域才会用到 BigInt 类型的数字。
# 数字的表示方法
# _ 的使用
下划线可用作分隔符(是语法糖的角色),使得数字具有更强的可读性。JavaScript 引擎会直接忽略数字之间的 _ 。
🌰 例子 / 下划线分割数字:
let billion = 1000000000; // before
let billion = 1_000_000_000; // after
2
# 科学计数法
在 JavaScript (许多编程语言中),使用
e表示为 10 的几次方,由 e 后面跟着的定量数字决定,可以是正数也可以是负数。
🌰 例子:
let billion = 1e9; // 10 亿,字面意思:数字 1 后面跟 9 个 0
# 二进制、八进制、十六进制
二进制和八进制数字系统很少使用,但也支持使用 0b 和 0o 前缀:
let a = 0b11111111; // 二进制形式的 255
let b = 0o377; // 八进制形式的 255
alert( a == b );
2
3
4
十六进制数字在 JavaScript 中被广泛用于表示颜色,编码字符以及其他许多东西。 0x ,然后是数字。
alert( 0xff ); // 255
alert( 0xFF );
2
对于其他进制,应该使用函数 parseInt 。
# 与数字类型有关的方法
# toString(base)
使用此方法 num.toString(base) 返回在给定 base 进制数字系统中 num 的字符串表示形式(将二进制数字转换为相应的 base 进制,对应反过来的方法是 parseInt(str, radix) 。)。
base 的范围可以从 2 到 36 。默认情况下是 10 。
- base=16 用于十六进制颜色,字符编码等,数字可以是
0..9或A..F。- base=2 主要用于调试按位操作,数字可以是
0或1。- base=36 是最大进制,数字可以是
0..9或A..Z。所有拉丁字母都被用于了表示数字。
🌰 例子 :
let num = 255
console.log(num.toString(16)) // 转为十六进制
console.log(num.toString(2)) // 转为二进制
2
3
4
🌰 例子 / 将较长的数字使用 36 数字系统表示:
console.log(12345678..toString(36)) // 7clzi
..两个点调用方法:想直接在一个数字上调用一个方法,比如上面例子中的toString,那么需要在它后面放置两个点..。这是因为 JavaScript 语法隐含了第一个点之后的部分为小数部分。如果我们再放一个点,那么 JavaScript 就知道小数部分为空,现在使用该方法。也可以使用括号分隔
(123456).toString(36)
# 数字的舍入
关于数字进行舍入的内建函数:
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移除小数点的所有内容(没有舍入)。例如,3.1变成3,-1.1变成-1。
常用的处理数字小数部分(移除)就是上述这些方法。
如果想要保留数字的小数部分(舍入到后 n 位),有两种方法:
toFixed(n):将数字舍入到小数点后n位(规则四舍五入,向上或向下舍入到最接近的值),例如:let num = 12.34; num.toFixed(1); // 12.31
2let num = 12.36; num.toFixed(1); // 12.41
2toFixed的结果是一个字符串。如果小数部分比所需要的短,则在结尾添加零(补上不足的小数位):let num = 12.34; alert( num.toFixed(5) ); // "12.34000"1
2乘除法:例如,要将数字舍入到小数点后两位,我们可以将数字乘以
100,调用舍入函数,然后再将其除回。例如:let num = 1.23456; Math.round(num * 100) / 100 // 1.23456 -> 123.456 -> 123 -> 1.231
2
# JavaScript 小数数字精度
JavaScript 中数字精度问题:
点击查看
在内部,数字是以 64 位格式 IEEE-754 (opens new window) 表示的,所以有 64 位可以存储一个数字:其中 52 位存储这些数字,11 位用于存储小数点的位置(对于整数,它们为零),而 1 位用于符号。
如果一个数字真的很大,则可能会溢出 64 位存储,变成一个特殊的数值 Infinity :
console.log(1e500) // Infinity
🌰 例子 / 一个常见的小数加法运算,并不是预期的结果:
alert( 0.1 + 0.2 ); // 0.30000000000000004
在 JavaScript 中,一个数字以其二进制的形式存储在内存中,一个 1 和 0 的序列。但是在十进制数字系统中看起来很简单的 0.1 , 0.2 这样的小数,实际上在二进制形式中是无限循环小数。
IEEE-754 数字格式通过将数字舍入到最接近的可能数字来解决此问题。这些舍入规则通常不允许看到「极小的精度损失」,但是它确实存在。
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
所以当对两个数字进行求和时,它们的「精度损失」会叠加起来。这就是为什么 0.1 + 0.2 不等于 0.3 。
解决方法:
- 使用
toFixed(n)对结果舍入。
🌰 例子:
let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // toFixed 总是返回一个字符串
alert( +sum.toFixed(2) ); // 使用一元加号将其强制转换为一个数字
2
3
- 将小数临时乘以小数位数的 10 的倍数,先将其转换为整数,进行数学运算,然后再除回相应的 10 的倍数。但是这种方法只可以减少误差,但不能完全消除误差。
🌰 例子:
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
2
小数的运算处理是不可能完全避免的。就算所有的价格数据都是整数,也避免不了打折计算结果的情况。所以最好的方法就是在得到计算小数的结果进行「剪掉尾巴」的处理,
提示
JavaScript 数字内部存在两个零, -0 和 0 ,这是因为在存储时,使用一位来存储符号,因此对于包括零在内的任何数字,可以设置这一位或者不设置。在大多数情况下,这种区别并不明显,运算符将它们视为相同的值。
# isFinite 和 isNaN
对于两个特殊的数值: Infinity ( -Infinity )(比任何数值都大的特殊数值)和 NaN (计算出错的结果),它们属于 number 类型,但不是「普通」的数字,因此,这里有用于检查它们的特殊函数:
isNaN(value)将其参数转换为数字,然后测试它是否为NaN:console.log( isNaN(NaN) ); // true console.log( isNaN("str") ); // true1
2注意:不能使用与
NaN全等比较,NaN独一无二的,它不等于任何东西,包括它自身。console.log(NaN === NaN)1⭐️
isFinite(value)将其参数转换为数字,如果是常规数字,则返回true,而不是NaN/Infinity/-Infinity,(可以理解为检验一个数字是否为有限值(不是NaN或者Infinity)):console.log(isFinite("15")) // true console.log(isFinite("str")) // true console.log(isFinite(Infinity)) // false1
2
3还被用于验证字符串值是否为常规数字:
let num = +prompt("Enter a number", ''); console.log(isFinite(num));// 结果会是 true,除非你输入的是 Infinity、-Infinity 或不是数字1
2
注意
在所有的数字方法函数中,包括 isInfinity ,空字符串或者仅有空格的字符串均被视为 0 。
提示
** 更可靠的比较方法 Object.is **:这是一个特殊的 JavaScript 内建方法,它类似于 === 一样对值进行比较,但它对于两种边缘情况更可靠:
NaN:Object.is(NaN,NaN) === true。- 值
0和-0是不同的:Object.is(0,-0) === false。(从技术上看,数字的字符位可能会不同,这就导致数字并不相同,即使其他所有位都为零)
其他情况, Object.is(a,b) 完成的比较结果与 a === b 结果相同。
这种比较方式经常被用在 JavaScript 规范中。当内部算法需要比较两个值是否完全相同时,它使用 Object.is (内部称为 SameValue (opens new window))。
提示
JavaScript 中检验用户的输入问题:现有一函数需要将用户输入的数值相加,返回相加后的结果。所以要判断用户的输入(完整考虑,不能仅仅只将用户的输入转换为数字):
function add(){
let a = +prompt('first num', 0)
if(!isFinite(a)) return alert('error')
let b = +prompt('second num', 0)
if(!isFinite(b)) return alert('error')
return alert(a + b)
}
2
3
4
5
6
7
8
9
10
# parseInt 和 parseFloat
前面所述,当我们需要将计算结果或者某一个值转换为数字类型,可以选择使用 + 或者 Number() 转换。使用这两种方法对于如果一个值不完全是数字(带有单位),就会失败:
console.log(+"100px") // NaN
但是对于字符串中存在空格(无论开头结尾),都会被忽略成功转换。所以这两种方法存在局限。
对于带有单位( '100px' 、 ‘12pt’ 、 “19€” )的数字字符串,要提取其中的数值,JavaScript 提供了 parseInt 和 parseFloat ,可以从字符串中读取出数字,直到无法读取:
parseInt返回一个整数;parseFloat返回一个浮点数;
🌰 例子:
console.log(parseInt('100px')) // 100
console.log(parseFloat('12.5em')) // 12.5
console.log(parseInt('12.5')) // 12 提取整数
console.log(parseFloat(3.14.159)) // 3.14 停止在第二个小数点
console.log(parseInt('a123')) // NaN 第一个符号即非数值,则停止读取,对于parseFloat也同理
2
3
4
5
6
7
提示
parseInt(str, radix) 的第二个参数: radix 指定了数字系统的基数,因此 parseInt 还可以解析十六进制数字、二进制数字等的字符串(转换为十进制整数):
console.log(parseInt('0xff', 16)) // 转换16进制的数为十进制
console.log(parseInt('ff', 16)) // 不带0x仍然有效
console.log(parseInt('2n9c', 36)) // 123456
2
3
4
# 其他数学函数
Math.random():返回一个从 0 到 1 的随机数(不包括 1。):console.log(Math.random()) // 0.51816405796950681与舍入的方法配合使用:
Math.floor(Math.random()*10) // 0~10之间的随机整数 Math.ceil(Math.random()*10) // 0~10之间的随机整数 Math.round(Math.random()*10) // *均衡获取0~10之间的随机整数1
2
3
更详细的生成随机数的方案:
点击查看
生成从
min到max的随机整数:错误方案 / 边缘值的概率会比其他值少 :
function randomInteger(min, max) { let rand = min + Math.random() * (max - min); return Math.round(rand); }1
2
3
4正确方案 / 调整取值范围的边界:
function randomInteger(min, max) { // 现在范围是从 (min-0.5) 到 (max+0.5) let rand = min - 0.5 + Math.random() * (max - min + 1); return Math.round(rand); }1
2
3
4
5正确方案 / 取范围从
min到max+1的随机数 :function randomInteger(min, max) { let rand = min + Math.random() * (max + 1 - min); return Math.round(rand); }1
2
3
4生成从
min到max的随机数:function random(min, max) { return min + Math.random() * (max - min) }1
2
3
Math.max(a, b, c)/Math.min(a, b, c):Math.max() - JavaScript | MDN (mozilla.org) (opens new window) 获取一组参数中(参数可以是一组数字,可以是数组)的最大值或者最小值:console.log(Math.max(1, 3, 2)); // expected output: 3 console.log(Math.max(-1, -3, -2)); // expected output: -1 const array1 = [1, 3, 2]; console.log(Math.max(...array1)); // expected output: 3 // 对于 Math.min() 使用方法同理。1
2
3
4
5
6
7
8
9
10
11如果有任一参数不能转换为数值,则返回值为
NaN。如果没有参数,结果为Infinity(-Infinity)。
提示
使用 Math.max() 或者 Math.min() 裁剪值:使某个方法的返回值始终小于或者大于某个值。
🌰 例子:
var x = f(foo);
if (x > boundary) {
x = boundary;
}
2
3
4
Copy to Clipboard
可以写成:
var x = Math.min(f(foo), boundary); // 只要返回值大于边界值就只返回边界值
# 数字类型总结
- 对于很多零(或者有很多小数位)的数字可以使用科学计数法
e简化表示数值。 - 对于不同的数字系统(不同进制的数字),在前添加相关的前缀,十六进制(
0x),八进制(0o)和二进制(0b),即可以在系统中写入数字。parseInt(str,base):指定的base数字系统 (2 ≤ base ≤ 36) 转换为十进制整数。num.toString(base):将数字转换为在给定的base数字系统中的字符串(二进制转换为其他进制)。
- 提取出带有单位的数字字符串:使用
parseInt/parseFloat进行转换,在特殊字符之前停止读取转换。 - 小数的舍入:使用
Math.floor,Math.ceil,Math.trunc,Math.round或num.toFixed(precision)进行舍入。 - 使用小数会有损失数字精度的问题。
- 更多的数值类型的数学函数来自 Math (opens new window) 对象。
