数据类型转换的那些坑:隐式类型转换
本文的讨论数据类型转换主要是指应用在逻辑判断中存在的转换,这种转换也被成为 JavaScript 的隐式类型转换,隐式类型转换可能会带来与逻辑预期不符的结果,所以需要明确这其中的坑。
if 判断
NaN、0、null、undefined、“” => false
开发中经常需要对某个值做 if 判断,然后决定需要执行的代码分支,在使用 if 判断时,可能会出现一些不符合主观预期的结果,例如:
let arr = []
if (arr) {
console.log("hello");
}
// hello
以上代码的 if 判断主观上可能认为是 false ,然而结果却是 true,所以打印出了 hello 。
在使用 if 进行判断时,表达式如果为单一值或者变量, 那么只有下列情况会返回 false:
- NaN
- 0
- null
- undefined
- “”(空字符串)
- false
除了以上情况外,其他都会返回 true ,所以下面的代码也是会按照 if (true) 来输出:
let a = [];
let b = {};
if (a) console.log('a'); // a
if (b) console.log('b'); // b
if (a && b) console.log('a && b'); // a && b
所以直接使用 if 来判断数组是否为空或者对象是否为空是不可靠的,编程时需要明确知道这里判断的到底是什么。
之所以会出现上面的问题,是由于 if 逻辑判断的表达式,最后是一个布尔值,所以会隐式转换为 Boolean 类型来判断,所以上面的代码相当于:
let a = [];
let b = {};
if (Boolean(a)) console.log('a'); // a
if (Boolean(b)) console.log('b'); // b
if (Boolean(a) && Boolean(b)) console.log('a && b'); // a && b
同理,空对象和空数组隐式转换为 Boolean 的结果为 true,所以下面的代码会输出 true:
console.log(Boolean([])); // true
console.log(Boolean({})); // true
等于 与 完全等于
这是两个符号,等于()与 完全等于(=)。
使用 等于 进行逻辑判断时,也会出现不符合预期的结果,例如:
console.log(null == undefined); // true
而使用 完全等于 则可以得到符合预期的结果:
console.log(null === undefined); // false
这是由于 与 = 判断的方式不同, 仅判断值是否相等,而 = 不仅判断值是否相等,也会判断类型是否相等。
等于
使用等于好做判断时是判断值是否相等,即表示要做一个隐式类型转换,转为的结果为 number
。
所以,下面的两行代码应该是等价的:
console.log(null == 0); // true
// 等价于下面的代码
console.log(Number(null) == 0); // true
同理,下面的代码也是等价的:
console.log([] == 0); // true
// 等价于下面的代码
console.log(Number([]) == 0); // true
所以, 等于的具体判断过程为:
- 两个对象的类型是否相同,如果相同,则直接对比值是否相同;
- 如果两个对象的类型不同,则先进行隐式转换,转为 Number 类型,然后判断值是否相同;
需要补充的一点是,如果两个比较对象的类型不同,且分别为 null
和 undefined
,则直接返回 true ,不在进行隐式类型转换。
于是可知,下面的判断将返回 false :
console.log(undefined == {}); // false
因为在隐式转换中,undefined 和 空对象 {} 无法转换为有意义的 Number 值,对 undefined 和 {} 的 Number 转换都将得到 NaN ,而 NaN 与任何值比对都将为 false ,即:
console.log(Number(undefined)); // NaN
console.log(Number({})); // NaN
console.log(NaN == NaN); // false
完全等于 =
完全等于与等于不同的是,使用完全等于进行判断时会进行值和类型的同时判断,如果类型不同则不会进行隐式类型转换,所以可以得到符合预期的严格结果。
所以,= 完全等于的判断过程为:
- 如果比较对象的类型不同,则为 false ;
- 如果比较对象的类型相同,但是值不同,依然为 false;
基于上述过程,下面的代码应该是好理解的:
console.log(null === undefined); // false
由于 null 和 undefined 是两个不同的基本类型,所以首先就类型不同了,也就没有必要比较值,结果当然为 false。
需要注意一点,下面的比较也将返回 false :
console.log(NaN === NaN); // false
这是由于 NaN 可以为任意值,所以 NaN 与任何值比较的结果都为 false ,也包括 NaN 自己。