学习链接
数据类型-Number
函数 toFixed(n) 将数字舍入到小数点后 n 位,并以字符串形式返回结果。
浮点数计算
在内部,数字全是以 64 位格式浮点数形式存储的,需要整数运算时,转为 32 位整数再计算。
1 位用于符号位,11 位用于存储指数部分,52 位用于存储小数部分(即有效数字)。
15 位的十进制数都可精确处理,超过 时不保证精度。
浮点数的精度损失
使用二进制数字系统无法 精确 存储 0.1 或 0.2,就像没有办法将三分之一存储为十进制小数一样。
因为 1/3 无法用 10 的整数次幂来进行精确表示,0.1 和 0.2 也无法用 2 的整数次幂来进行精确表示。
IEEE-754 数字格式通过将数字舍入到最接近的可能数字来解决此问题。
这些舍入规则容易让人们忽略掉“极小的精度损失”,但是它确实存在。
0.1 + 0.2 !== 0.3 // true0.1 + 0.2 // 0.30000000000000004
0.1.toFixed(20) // '0.10000000000000000555'0.2.toFixed(20) // '0.20000000000000001110'(0.1 + 0.2).toFixed(20) // '0.30000000000000004441'0.3.toFixed(20) // '0.29999999999999998890'
当我们对两个数字进行求和时,它们的“精度损失”会叠加起来。
这就是为什么 0.1 + 0.2 不等于 0.3。
解决方案
最可靠的方法是借助方法 toFixed(n) 对结果进行舍入
let sum = 0.1 + 0.2;sum.toFixed(2) // '0.30'
请注意,toFixed 总是返回一个字符串。
我们可以将数字临时乘以 100(或更大的数字),将其转换为整数,进行数学运算,然后再除回。当我们使用整数进行数学运算时,误差会有所减少,但仍然可以在除法中得到:
(0.1 * 10 + 0.2 * 10) / 10 // 0.3(0.28 * 100 + 0.14 * 100) / 100 // 0.4200000000000001
因此,乘/除法可以减少误差,但不能完全消除误差。
补充
9999999999999999 // 显示 10000000000000000
出现了同样的问题:精度损失。有 64 位来表示该数字,其中 52 位可用于表示有效数字,但这还不够。所以最不重要的数字就消失了。
JavaScript 不会在此类事件中触发 error。它会尽最大努力使数字符合所需的格式,但不幸的是,这种格式不够大到满足需求。
常规数字检测
isNaN(value)
先将其参数转换为数字(调用Number()),然后检测它是否为NaNisFinite(value)
先将其参数转换为数字(调用Number()),如果它是常规数字,而不是NaN/Infinity/-Infinity,则返回trueNumber.isNaN(value)
检查一个值是否为NaN,只对数值有效,不进行转换Number.isFinite(value)
检查一个值是否为常规数字,只对数值有效,不进行转换
isNaN(NaN) // trueisNaN("NaN") // trueNumber.isNaN(NaN) // trueNumber.isNaN("NaN") // falseNumber.isNaN(1) // falseisFinite(25) // trueisFinite("25") // trueNumber.isFinite(25) // trueNumber.isFinite("25") // false
字符串转数字
“硬” 转换
使用加号 + 或 Number() 的数字转换是严格的。如果一个值不完全是一个数字,就会失败
+"100px" // NaN
唯一的例外是字符串开头或结尾的空格,因为它们会被忽略。
“软” 转换
使用 parseInt/parseFloat 进行“软”转换,它从字符串中读取数字,直到无法读取为止,然后返回在发生 error 前可以读取到的值。
(与 Number.parseInt/Number.parseFloat 完全一致)
函数 parseInt 返回一个整数,而 parseFloat 返回一个浮点数
parseInt(' 100px ')// 100parseFloat(' 12.5em') // 12.5parseInt(' 12.3 ') // 12,只有整数部分被返回了parseFloat(' 12.3.4 ') // 12.3,在第二个点出停止了读取parseInt('a123') // NaN,第一个符号停止了读取
parseInt(str, radix)
parseInt() 函数具有可选的第二个参数。它指定了数字系统的基数,因此 parseInt 还可以解析十六进制数字、二进制数字等的字符串:
alert( parseInt('0xff', 16) ); // 255alert( parseInt('ff', 16) ); // 255,没有 0x 仍然有效alert( parseInt('2n9c', 36) ); // 123456
特殊数值
+0 和 -0
-0 === +0 // true0 === -0 // true0 === +0 // true+0 // 0-0 // 0(-0).toString() // '0'(+0).toString() // '0'(1 / +0) === (1 / -0) // false(1 / +0) // Infinity(1 / -0) // -Infinity
NaN
Not a Number
typeof NaN // 'number'NaN === NaN // false5 - 'x' // NaNMath.sqrt(-1) // NaN0 / 0 // NaN
Infinity 和 -Infinity
1/0 // Infinity-1/0 // -Infinity// 数学计算中当作无穷0 * Infinity // NaN0 / Infinity // 0Infinity / 0 // InfinityInfinity + Infinity // InfinityInfinity * Infinity // InfinityInfinity - Infinity // NaNInfinity / Infinity // NaN// 与 undefined 计算都是 NaN
Object.is()
有一个特殊的内建方法 Object.is,它类似于 === 一样对值进行比较,但它对于两种边缘情况更可靠:
NaN:Object.is(NaN, NaN) === true0和-0:Object.is(0, -0) === false
在所有其他情况下,Object.is(a, b) 与 a === b 相同。
这种比较方式经常被用在 JavaScript 规范中。当内部算法需要比较两个值是否完全相同时,它使用 Object.is(内部称为 SameValue)。
