JavaScript梗图详解
- 前几天我看到了一张JavaScript的梗图,虽然看完之后哈哈大笑,但是有些东西我并不知道为啥是这样,只是知道了有这么一件事,但是不知道其中的原理,所以我今天来开坑把这个图上的JavaScript知识点整理一下
开坑一时爽,填坑火葬场,看我这个坑要多久才能填上 (2020/05/12开坑)
截至发送事件 (2020/06/29) 这个坑我才填上,我的拖延症没救了吧
1. typeof NaN == “number”
-
NaN 的意思是说明这个值不是数字,例如我们在把字母转换成整数或者浮点数时,他返回的值就是 NaN
-
NaN 是一种特殊的 number 类型,NaN 与任何值都不相等,与他自己也不相等
-
所以在判断某个值不是数字的时候不能使用
==NaN ,这样的话无论他是不是数字都返回 false ,这里应该使用isNaN() 函数来判断他是否是 NaN 值 -
另外附上其他类型的 typeof 返回值
- undefined:undefined
- null:object
- string:string
- number:number
- boolean:boolean
- function:function
- object:object
typeof 另一个有意思的题
- 在查找 nan 的资料的时候正好看到这个题,也是十分有意思的题
- 原帖里的凯斯的答案已经解释的相当清晰了,感谢凯斯的讲解!
- 下面我只是简单复述一下他的答案,感兴趣的可以去原帖仔细了解
1 2 3 4 5 | typeof 1/0; //NaN(这个NaN不是字符串类型,是数值类型) typeof typeof 1/0; //NaN(这个NaN不是字符串类型,是数值类型) typeof(1/0); //"number" typeof typeof(1/0); //"string" typeof(typeof 1/0); //"number" |
- 第一个是运算符优先级的问题,大家可以去MDN上的运算符优先级去查看
- 这里我直接给出结论,typeof 的优先级比除号高,所以其实这个计算是这样的
1 | (typeof 1)/0 |
- typeof 1计算出来结果等于字符串 “number” 再除以 0,所以这里就变成 NaN 了
- 第二个用到 typeof 是右结合型的,所以就是从右往左开始计算,这个计算就是这样的
1 | (typeof (typeof 1))/0 |
- 先typeof 1返回字符串 “number”,再 typeof 返回字符串 “string”,字符串除以数字0,所以结果还是 NaN
- 第三个感觉比较简单了,Infinity 是数字类型,所以typeof输出的是字符串 “number”
- 第四个和第三个一脉相承,迪桑返回的是字符串 “number”,在typeof输出的就是字符串 “string”
- 第五个是第一个的加强版,第一个算出的结果是 NaN ,正好就是我们梗图的第一个,直接输出 “number”
JavaScript精度问题
- 下面的笔记根据 JavaScript小数精度问题 及查找的资料来讲解
- JavaScript对于数据储存使用的是 IEEE754 标准里的 双精度存储数字 (64位)
- IEEE754 标准里面有符号位 1 位,指数位 11 位,有效数 52 位,这样就导致在十进制和二进制转化的时候会出现问题
大数精度问题
-
9999999999999999 == 10000000000000000 16个9等于一兆 -
这个是JavaScript的大数精度问题,因为如下图 16个9 转换成二进制后所占用的数字就已经达到了 53 位,有效数字已经放不下了,所以才会造成大数精度问题
-
就此我们也可以推知我们不发生大数精度的问题最大存储的数字大小 2^53 = 9007199254740992,大于这个数都有可能发生大数精度问题
-
解决办法:把数字转化为字符型,这样肯定不能发生精度的问题了
小数精度问题
-
0.5+0.1 == 0.6 true,0.1+0.2 == 0.3 false 0.1 + 0.2 != 0.3
-
这道题我刚看到的时候感觉是精度的问题,很多编程语言里的小数都有精度的问题
-
十进制小数转化为二进制小数的时候也会出现误差,例如
-
0.1 => 0.0001 1001 1001 1001 (1001的循环)
-
0.2 => 0.0011 0011 0011 0011 (0011的循环)
-
所以相加之后会出现误差
-
解决办法:可以使用
toFix() 四舍五入保留到小数后几位 (注意,toFix 后的结果是字符串类型的,需要转化为数字)
精度问题小结
- 其实精度问题比较好理解,在十进制里也有精度的问题
- 例如 0.3333… + 0.3333… + 0.3333… = 0.9999… 和 1/3 + 1/3 + 1/3 = 1 这里是分数转化为小数的时候丢失了精度
- 在计算机中是二进制与十进制的转化中丢失的精度
Math 里的 max方法和 min 方法
-
求最大值的方法没有参数的时候返回的是 -Infinity,但是最小值的方法没有参数的时候返回的是 Infinity
-
但是在网上找的的结果 (MDN, W3school, 菜鸟教程) 里都只是给出了一个结论,并没有给出为什么是这个值
-
然后我找到了 Google JS 引擎 下载了源代码,查找了 math.js
-
貌似源码也没有给出注释
js 中的符号特性
- 后面几个基本上都是一些 JavaScript 的运算符号的特性,而且顺序比较乱,所以这里归为一大类
js 里的加号
1 2 3 4 5 6 7 8 9 10 11 12 | // 1. 两个空数组相加等于一个空字符串 [] + [] = "" // 2. 数组加对象等于 "[object Object]" [] + {} = "[object Object]" // 3. 对象加数组等于 0 {} + [] = 0 // 4. 三个 true 相加和 3 全等 true + true + true === 3 // 5. !+[]+[]+![] (!+[]+[]+![]).length = 9 // 6. 数字加字符串 9 + "1" = "91" |
-
1 的情况
- 在js遇到不能计算的情况时,就会进行默认转换
- 这时 [] 就会被替换成 ‘’ ,所以两个相加也为空字符串
-
2,3 的情况 (这里我引用贺师俊的回答,他写的十分清楚了)
先说 [] + {} 。一个数组加一个对象。
加法会进行隐式类型转换,规则是调用其 valueOf() 或 toString() 以取得一个非对象的值(primitive value)。如果两个值中的任何一个是字符串,则进行字符串串接,否则进行数字加法。
[] 和 {} 的 valueOf() 都返回对象自身,所以都会调用 toString(),最后的结果是字符串串接。[].toString() 返回空字符串,({}).toString() 返回“[object Object]”。最后的结果就是“[object Object]”。
然后说 {} + [] 。看上去应该和上面一样。但是 {} 除了表示一个对象之外,也可以表示一个空的 block。在 [] + {} 中,[] 被解析为数组,因此后续的 + 被解析为加法运算符,而 {} 就解析为对象。但在 {} + [] 中,{} 被解析为空的 block,随后的 + 被解析为正号运算符。即实际上成了:
{ // empty block }
+[]
即对一个空数组执行正号运算,实际上就是把数组转型为数字。首先调用 [].valueOf() 。返回数组自身,不是primitive value,因此继续调用 [].toString() ,返回空字符串。空字符串转型为数字,返回0,即最后的结果。
-
参考文章:Javascript中{}+[]===0为true,而[]+{}===0为false,因为啥,精彩的javascript对象和数组混合相加,JS中{}+[]和[]+{}的返回值情况是怎样的 贺师俊的回答
-
4 的情况
- boolean 遇到 + 会转化为 number
-
5 长度为 9 是他们相连接后是 “truefalse”
- ! + [] 为 true
- 中间的 [] 让两个字符串相连接
- 最后的 ![] 为 false
-
6 比较简单了,加号只要有一个字符串,加号就会变成字符串的拼接
js 里的减号
- js里的减号默认是转化为 Number 类型然后计算的
1 2 3 4 | // 1. true - true = 0 // 2. 91 - "1" = 90 |
js 里面的相等
== 只要值相等就好,而=== 既要数值相等,又要类型相等
1 2 3 4 5 6 | // 1. true == 1 true true === 1 false // 2. [] == 0 true {} == 0 false |
- 1 是相等和全等的区别
- 2 的第二行也是把 {} 解析成了 block 类型,所以其实是
{}; ==0 ,所以会报错 - 要是写成
({}==0) ,或者0=={} 都可以