前言

昨天在朋友圈看到了这张有趣的图

image-20210314162014551

那我们今天就来讲讲这个图吧

正文

Typeof

1
typeof NaN

因为typeof只能返回下面的东西

file

所以它只能返回个number了,而且NaN一般是在想把什么东西转化成number类型但是转化失败了才会出现的结果,某种意义上还是说的过去的

image-20210314162938150

浮点数精度

1
2
3
4
9999999999999999			// 10000000000000000
0.1 + 0.5 == 0.6 // true
0.1 + 0.2 == 0.3 // false
1.335.toFixed(2) == 1.33 // true

JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示,而我们知道,想用有限的位来表示无穷的数字,显然是不可能的,因此会出现一些列精度问题:

  • 浮点数精度问题,比如 0.1 + 0.2 !== 0.3
  • 大数精度问题,比如 9999 9999 9999 9999 == 1000 0000 0000 0000 1
  • toFixed 四舍五入结果不准确,比如 1.335.toFixed(2) == 1.33

有三种思路来解决这个问题

  • 考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));
  • 将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1*2)/3
  • 把浮点数转化为字符串,模拟实际运算的过程。

不过其实只有第三种是完全可行的

先来看第一种方案,在大多数情况下,它可以得到正确结果,但是对一些极端情况,toFixed 到 12 是不够的,比如:

1
2
210000 * 10000  * 1000 * 8.2    				// 17219999999999.998
parseFloat(17219999999999.998.toFixed(12)); // 17219999999999.998,而正确结果为 17220000000000

第二种方案也有一些问题,并不是完全可行

1
2
// 这两个浮点数,转化为整数之后,相乘的结果已经超过了 MAX_SAFE_INTEGER
123456.789 * 123456.789 // 转化为 (123456789 * 123456789)/1000000,结果是 15241578750.19052

所以,最终考虑使用第三种方案,目前已经有了很多较为成熟的库

这些库不仅解决了浮点数的运算精度问题,还支持了大数运算,并且修复了原生toFixed结果不准确的问题。

Math.max和Math.min

问就是看文档,其实没啥好记的,当成特殊情况下了解一下就可以了

image-20210314164236982

image-20210314164259613

奇怪的 + - !

1
2
3
4
5
6
7
[] + []		// ""
[] + {} // [object Object]
{} + [] // 0
true + true + true === 3 // true
true - true === 0 // true
9 + "1" // "91"
91 - "1" // 90

这是把+丢到一个表达式前面会发送的事情

简单来说就是会调用Number()把表单式转化为number类型

image-20210314165922618

这是传统意义上的+会发生的过程

image-20210314184934640

翻译一下

  • 把左右两边转化成原始类型
  • 如果一边是字符串,把另一边转成字符串做拼接
  • 否则把两边都转成数字进行+运算

这是把-丢到一个表达式前面会发送的事情

image-20210314185807857

简单来说就是调用Number()转成数字然后取反(正负的反)

这是传统意义上的-会发生的过程

image-20210314185949323

翻译一下:把两边都转成数字进行运算

然后这是!会发生的

image-20210314190713166

简单来说就是调用Boolean()然后取反

顺带一提,这个表达式,你以为是对象加数组

1
{} + []

其实是这样的

1
2
3
{}

+[]

上面的对象会被解析成一个代码块,然后只剩下+[],而Number([])的结果就是0

再顺带一提,这个东西

1
(!+[]+[]+![]).length

运行起来其实是这样的

1
2
3
4
5
(!+[]    +   []   +    ![]).length
(!0 + [] + false).length
(true + [] + false).length
(true + "" + false).length
("truefalse").length // 9

== 和 ===

==看这篇:https://www.sakura-snow.com/archives/142

===就是在==的基础上不进行类型转化而已,类型不一样直接返回false