JS[]==![]究竟发生了什么

1,760 阅读4分钟

一、 引子

先上题,得出心中答案,打开浏览器点开F12,复制下面代码,看看结果。

console.log( [] == ![] ) console.log( {} == !{} )

剖析一下,主要分为:

  1. 逻辑运算符的优先级,
  2. {}[]复杂数据类型如何转换;
  3. ==JS的数据类型的强制转换比较;

二、 逻辑运算符的优先级

运算符优先级本身是一种规则,该规则在计算表达式时控制运算符执行的顺序。具有较高优先级的运算符先于较低优先级的运算符执行。

先看MDN运算符优先级图表截取:

优先级 运算类型 关联性 运算符
20 圆括号 n/a ( … )
19 new (带参数列表) 从左到右 new … ( … )
函数调用 从左到右 … ( … )
16 逻辑非 从右到左 ! …
一元加法 从右到左 + …
一元减法 从右到左 - …
10 等号 从左到右 … == …
6 逻辑与 从左到右 … && …
5 逻辑或 从左到右 … || …

MDN完整地址

在截取的表格中可以清晰的看到,逻辑非!的优先级明显高于==等号的有优先级,因此第一个问题,在[] == ![]中最优先运算的是![],然后才是==比较。

三、 复杂的数据类型如何转换

console.log(![]) // false,这个结果相对好理解

注意: !带有隐式转换
1、undefined(未定义,找不到值时出现)

2、null(代表空值)

3、false(布尔值的false,字符串"false"布尔值为true)

4、0(数字0,字符串"0"布尔值为true)

5、NaN(无法计算结果时出现,表示"非数值";但是typeof NaN==="number")

6、""(双引号)或''(单引号) (空字符串,中间有空格时也是true

6种值转化为布尔值时为false

当前结论 ![] == false

当然,在使用==时永远不要大意!参见 附1


接下来,难题在于,[]如何转化进行比较。

请先记住一个比较的基本规则:

数组与数值进行比较,会先转成数值,再进行比较;与字符串进行比较,会先转成字符串,再进行比较;与布尔值进行比较,两个运算子都会先转成数值,然后再进行比较。

遵循上边的规则(左侧x为数组时),需要将[]false一并转化为数字类型后再进行比较。 OK,那么这个规则是谁说的算的呢? 截取一张知乎大佬贴的Es5 规范元知识图,上述比较参见 7 条。附2

图1-JS源码==Es5规范

参照第7条,ToNumber(false) // 0 为啥呢?上图

图2-Es5 9.3ToNumber方法

[]依照图1,进入第9条,使用ToPrimitive([]),上图

图3-ToPrimitive方法

好吧,要根据类型默认使用DefaultValue方法,上图

图4-[DefaultValue]默认方法

图4.1-String值为空情况

[]属于字符串hint,那么执行toString()

console.log([].toString()) // "";

终于,表达式看起来不费劲了,"" == false; 其实现在我们已经看到答案了,但是依据Es5==的规范,我们还需要将字符串和布尔类型转化为数字类型最终比较; false参照图2,字符串参照图1第5条,ToNumber("") // 0;

每次对比Es5规范真的好麻烦,所以

结尾总结了一下可以快速判断==转化判断依据的原则,不必每次都参照图1啦 - 附3

完美

0 == 0 // true

附1 相等运算符(==)隐藏的类型转换,会带来一些违反直觉的结果,下面整理一些:

0 == ''             // true
0 == '0'            // true
 
2 == true           // false
2 == false          // false
"2" == true         // flase
// 参见图1第7条
 
false == 'false'    // false
false == '0'        // true
 
false == undefined  // false
false == null       // false
null == undefined   // true


 
' \t\r\n ' == 0     // true
// \t \r \n都是转义字符,空格就是单纯的空格,输入时可以输入空格
// \t 的意思是 横向跳到下一制表符位置
// \r 的意思是 回车
// \n 的意思是回车换行

附2

中文版

附3

  • x == y同类型原则总结:

    1. Number比数值(+0,-0相等);
    2. String比长短与字符序列(charCode);
    3. Booleanfalse == false; // true;
    4. 复杂数据类型比较引用地址;
  • x == y不同基础数据类型比较原则总结:

    1. x或y出现NaN一定返回false;
    2. x或y出现Boolean一定全部转化数字后在比较;
    3. x或y出现Number一定全部转化数字后比较;
  • x == y 包含复杂数据类型原则:

    1. x或y出现复杂数据类型通过valueOf()toString()转化为基本数据类型, 然后参照上述规则比较;
  • x == y特殊总结:

    1. NullUndefined除彼此或自身外,一律返回false;
    2. NaN == NaN; // false

引用原地址:

  1. www.zhihu.com/question/29… // 知乎
  2. blog.csdn.net/qiqi_77_/ar… // CSDN
  3. lzw.me/pages/ecmas… // ES5规范中文站