前言
JavaScript作为一门弱类型语言,并不像C、Java那样有明确的类型定义如int、boolean、string、float、double等数据类型,而js同时又是一门脚本语言,逐行编译运行的,为了防止运行出错,就存在了变量类型的隐式转换
本人使用js也有一段时间了,但是对这个转换规则还是有点不理解全面,所以从网上学习回来,总结了这个隐式转换规则,从此以后不再纠结于这个东西,请往下看
转换规则
运算符的转换规则
- -左右两边的值会被转换成number再进行运算(* % / 也类似)
- +左右两边的值如果都为number,则进行正常的数值相加,否则判定为字符串拼接,将两个值转换为string后进行拼接
- 如果是存在复杂类型运算,会先将复杂类型转换为原始类型(Primitive),再进行运算,转换的过程如下:
先调用复杂类型对象上的valueOf()方法,如果返回值的不是原始类型,则调用toString()方法 - undefinde或null与非string类型的原始类型相加时,先将两边转换为number类型,所以总是会等于NaN
- undefinde或null与string类型,将前者转换为string类型进行字符串拼接
等号(==)两边对比的转换规则
- !后面的值会直接转换成boolean
- 对于原始类型之间的比较(==),如果两边类型一致,则直接进行比较,否则会先都转换为number类型,再进行比较
- 对于复杂类型与原始类型之间的运算,
- 复杂类型与复杂类型之间的比较,则是比较其内存地址是否相等
- 还有一种特殊情况就是undefined和null,undefined == null 永远为true,undefined和null与其他类型的值进行比较时永远为false
下面是在网上偷的一张图片,能够很好解释不同类型之间比较时的类型转换:
非布尔值转换为布尔值
ECMA规范:
非布尔类型转换为布尔类型时:
长度为0的字符串、undefined、null、0、±0、NaN会转换为false
非0且不为NaN的number类型、长度大于0的字符串、复杂类型会转换为true
例子解析
1+{a:1}
js
代码解读
复制代码
console.log(1+{a:1}) // '1[object Object]'
{a:1}是object类型,会先调用valueOf()方法,依旧返回{a:1},不为原始类型,则调用toString()方法,返回'[object Object]',为string类型,ok,进行字符串拼接,得到上面的结果
为了验证是不是这个过程,我们先重写toString方法,使其返回'{a:1}'
结果如下:
继续改写valueOf()方法,使其返回1
结果如下:
看来确实是这样的转换过程
undefined和null与其他类型的+运算
js
代码解读
复制代码
console.log(undefined+1) // undefined + 1 -> NaN + 1 = NaNNaN
console.log(undefined+'1') // undefined + '1' -> 'undefined' + '1' = 'undefined1'
console.log(null+1) // null + 1 -> 0 + 1 =1
console.log(null+'1') // null + '1' -> 'null' + '1' = 'null1'
console.log(null+undefined) // null + undefined -> 0 + NaN = NaN
console.log(undefined+[1,2]) // undefined + [1,2] -> 'undefined' + '1,2' = 'undefinde1,2'
console.log(null+[1,2]) // null + [1,2] -> 'null' + '1,2' = 'null1,2'
![] == []
js
代码解读
复制代码
console.log(![] == []) // true
首先,等式左边为![],存在!,将[]直接转换为boolean类型,![] -> !true = false
所以 (![] == []) -> (false == []) -> (0 == 0) = true
1+{} 与 {}+1
js
代码解读
复制代码
{}+1 // 1
1+{} // '1[object Object]'
一开始以为 {}+1 的值会是 '[object Object]1',结果却是1,其实并不是转换的问题,而是{}的问题,解释如下:
1+{},因为+在前,所以{}被当成运算符,它的值是'[object Object]',所以整个运算会自动类型转换 {}+1,{}在前,整个语句并没有被解析成一个表达式,被分开执行,就变成了:
js
代码解读
复制代码
{
};
+1
于是真正的语句就变成了+1,结果就是1了
只要加个小括号,就能去除二义性了
js
代码解读
复制代码
({})+1)