前言
阅读 现代Javascript教程过程中记录了一些忽略的点,知其然知其所以然,温故而知新,文章分QA两部分,知道的同学可以直接划过。
Question
- JS 对于数字是怎么存储的?
- 如何判断一个数字是整数?
- 最大安全数是多少?为什么?
- JS 能表示的最大数字是多少?为什么?
- 精度问题是怎么产生的?如何解决?
- 转换数字都有哪几种方式?
- NaN的比较怎么相等?
null>0?null==0?null>=0?- toFixed是怎么进行舍入的?
- BigInt 可以被JSON化么?
Answer
JS 对于数字是怎么存储的?
JavaScript 中的常规数字以 64 位的格式 IEEE-754 存储,也被称为“双精度浮点数”。
| 比特长度: | 1 | 11 | 52 |
|---|---|---|---|
| 名称: | S | Exp | Fraction |
| 比特编号: | 63 | 62至52 偏正值(实际的指数大小+1023) | 51至0位编号(从右边开始为0) |
ps:JS没有其他语言的 int,float,double 之分,存储结构全是64位的。
如何判断一个数字是整数?
Number.isInteger = Number.isInteger || function(value) {
return typeof value === "number" &&
isFinite(value) &&
Math.floor(value) === value;
};
最大安全数是多少?为什么?
最大安全数是Number.MAX_SAFE_INTEGER,是一个值为 9007199254740991 的常量【2^53 - 1】。因为IEEE-754只有52位是用于尾数存储。
JS 能表示的最大数字是多少?为什么?
最大数字是Number.MAX_VALUE 约等于 1.7976931348623157 × 10^308。因为最大的话就是指数拉满,尾数拉满,其中尾数拉满就是最大安全数,但是需要注意尽管用11位表示指数位,但为了方便计算忽略正负的差异,实际上是有一个偏正值的【这样就全是正的了】所以指数拉满是 1023【2^10 - 1】。综上最大数字为 2^1023 * Number.MAX_SAFE_INTEGER
精度问题是怎么产生的?如何解决?
一个数字以其二进制的形式存储在内存中,一个 1 和 0 的序列。但是在十进制数字系统中看起来很简单的
0.1,0.2这样的小数,实际上在二进制形式中是无限循环小数。使用二进制数字系统无法 精确 存储 0.1 或 0.2,就像没有办法将三分之一存储为十进制小数一样。
解决方案:
- 将浮点数转为整数运算,再对结果做除法
- 把浮点数转化为字符串,模拟实际运算的过程
- 直接使用现成强大的库decimal、number-precision、mathjs等【直接用第三方库吧,毕竟经历过大家检验的】
转换数字都有哪几种方式?
- 一元
+ - 显式调用
Number(xxx) parseInt(string[, radix])转换为整数,转换算法是去除首尾空格,从前向后扫描,碰到第一个非数字相关字符停止扫描返回结果,如果第一个字符就和数字无关则返回NaNparseFloat(string)和parseInt几乎一致,但是缺少第二个基数可选参数
ps: 一元 +运算转换不了 BigInt 类型,Number() 则可以
NaN 的比较怎么相等?
NaN == NaN 为 false,而 Object.is(NaN,NaN)为 true。这是 Object.is 和 === 区别之一,还有一点不同是对于 +0 和 -0 的比较对待,Object.is 视为 false,而 === 视为 true
ps:在 Map 数据结构中用NaN的比较算法是Object.is
null>0?null==0?null>=0?
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
因为相等性检查
==和普通比较符> < >= <=的代码逻辑是相互独立的。进行值的比较时,null会被转化为数字,因此它被转化为了0。这就是为什么(3)中null >= 0返回值是 true,(1)中null > 0返回值是 false。另一方面,
undefined和null在相等性检查==中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。这就解释了为什么(2)中null == 0会返回 false。
toFixed 是怎么进行舍入的?
很多人说是银行家算法,但是并不是银行家算法四舍六入五取偶(又称四舍六入五留双)
具体查看规范【英文版】:262.ecma-international.org/6.0/#sec-nu…
规范【中文版】:yanhaijing.com/es5/#429
这里有个很有意思的题为什么 6.35.toFixed(1) == 6.3?
根据规范公示去算的话 保留一位小数 要么6.3 要么6.4,这和6.35减下来都是0.05,照规范应该选大的6.4啊,为啥最后会是6.3呢?【用计算机算,不要用人算你就知道咋回事了,是精度造成的】
63/10 - 6.35 // -0.04999999999999982
64/10 - 6.35 // 0.05000000000000071
BigInt 可以被JSON化么?
不能