最常见的==和!=造成的隐式转换,网上已经有很多人总结了,总结起来就一张图:
Object → String → Number
↑
Boolean
不同类型之间做==或!=运算,会按箭头方向转换直到类型相等。
(undefined, null和NaN后面再细说)
下面是重点,到底哪些运算会造成隐式转换呢?
按照我的理解,除了===和!==比较运算,其他所有的运算都会造成隐式转换。
JS的运算符可以归纳为7大类:
1. 算术运算符
2. 赋值运算符
3. 比较运算符
4. 逻辑运算符
5. 三元运算符
6. 位运算符
7. 字符串连接运算符
我们来逐个验证。
1.算术运算符
+, -, *, /, %, ++, –
转换规则1:所有类型均转换为Number;
转换规则2:null会转换为0,undefined会转换为NaN
console.log(null + 1); //1 +运算符作为字符串连接符的例子请看第7条
console.log(undefined - 1); // NaN
console.log([] * 1); //0 []先转换为String:'',再转换为0
console.log([1] / 1); //1 [1]先转换为String:'1',再转换为1
console.log({} % 1); //NaN {}先转换为String:'[object Object]',再转换为NaN:
var a = true; console.log(++a); //2 不能写成++true, ++运算只能作用于变量
var a = false; console.log(--a); //-1
2.赋值运算符
=,+=,-=,*=,/=,%=
赋值运算的隐式转换与算术运算同理,这里就不再验证了。
3.比较运算符
==, !=, >, >=, <, <=(不讨论绝对等于)
转换规则1:若均为基本类型,不需转换;若均为复杂类型,做>和<比较需转换为String再比较;
转换规则2:若类型不同,按照最上图进行转换,直到类型相等,最终转换为String或Number;
比较规则1:Number直接比较;String逐字符比较他们的unicode值;复杂类型比较引用的对象是否相同。
比较规则2:NaN既不等于任何值,也不大于和小于任何值;
比较规则3:undefined == null 返回true,两者和除此之外所有类型都不相等。
console.log('true' == true); //false 均转换为Number,既 NaN == 1
console.log([] != true); //true 均转换为Number,既 0 != 1
console.log('a' > 1); //false 均转换为Number,既NaN>1
console.log('a' > '1'); //true 直接比较unicode值
4.三元运算符
a ? b : c
转换规则1:第一个值会转换为Boolean;
转换规则2: 空字符串/0/null/NaN/undefined会转换为false,其他为true
console.log( [] ? 1 : 2); //1
5.逻辑运算符
&&, ||, !
&& 和 || 转换规则:所有类型均先转换为Boolean做运算,再根据各自运算规则返回其中的一个原值;
! 转换规则:所有类型均转换为Boolean,并返回该Boolean的取反
console.log(undefined && 1); //undefined
console.log({} || 'a'); //Object {}
console.log(!undefined); //true
6.位运算符
~, &, |, ^, <<, >>, >>>
转换规则1:所有类型均转换为Number;
转换规则2:NaN, null和undefined都会转换为0(注意,与算术运算符不同)
console.log(~undefined); //-1
console.log('25'&[3]); //1
console.log({}|NaN); //0
console.log({}^[1]); //1
console.log(NaN<<1); //0
console.log({}>>1); //0
console.log(['6.6']>>>0); //6
7.字符串连接运算符
+
转换规则:若运算符前后有一个为复杂类型或String类型,两者均转换为String类型
console.log(null+[]+1); //null1
这么多的隐式转换,简直是防不胜防。
那么为什么只有==这个运算的隐式转换这么受人关注呢?
一个原因是,其他运算符造成的隐式转换就是我们想要的,比如算术运算符我们就是想得到Number,但是==运算不同,它的隐式转换并不可控,出的意外更多;
另一个原因是,我们完全可以用===来避免这种隐式转换,而其他的运算符就没有这种待遇了。