隐式类型转换会让代码晦涩难懂,也会减少冗余,让代码更简洁
- 字符串和数字之间的隐式类型转换
const a = "32";
const b = 54;
// a + a = "3232";
// a + b = "3254";
// b + d = 57;
const arr1 = [1, 2];
const arr2 = [3, 4];
// arr1 + arr2 = "1,23,4";
- 根据ES5规范,如果某个操作数是字符串或者能转换为字符串的话,+操作符进行拼接操作,数组的valueOf()操作无法得到一个基本类型值,于是它转而调用toString(),因此上面的两个数组变成了"1, 2"和"3, 4",+拼接为"1, 23, 4";
- 运算符会将字符串强制转化为数字,因为数字才有这个操作符,数组会先调用toString()转化为字符串,然后再转化为数字。
const a = "3.14";
const b = a - 0;
console.log(b); // 3.14
const c = [4];
const d = [2];
console.log(c - d); // 2
- 布尔值到数字的隐式类型转换
// 用于判断参数是否只有一个为真值
function onlyOne() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
if (arguments[i]) {
sum += arguments[i];
console.log(sum);
}
}
return sum == 1;
}
- 隐式类型转换为布尔值
- 条件判断
- falsely变量,判断条件为false,truly变量,条件判断为true
- 以下是falsely变量,除此之外都是truly变量
0(+0,-0)NaN""nullundefinedfalse
- 条件判断语句
- if()语句中的条件判断表达式
- for语句中条件判断表达式
- while循环中的条件判断表达式
- 三目运算符中的条件判断表达式
- 逻辑运算法|| ,&& 作为条件判断表达式的部分
- null和undefined之间的相等比较
- null == undefined (true),也就是说,在==中,null和undefined是一回事,可以互相进行隐式类型转换:
const a = null;
const b;
a == b; // true
b == null // true
a == false; //false
b == false; // false
a == ""; // false
b == ""; //false
a == 0; // false
b == 0; // false
- 对象与非对象之间的相等比较
-
关于对象(对象、函数、数组)和基本类型(字符串、数字、布尔值)之间的比较
(1) 如果Type(x)是字符串或者数组,Type(y)是对象,则返回x==ToPrimitive(y)的结果 (1) 如果Type(x)是对象,Type(y)是字符串或者数组,则返回ToPrimitive(x)==y的结果
const a = 42;
const b = [42];
a == b; // true
// [42]会首先调用ToPrimitive抽象操作,返回"42",变成"42" == 42,然后又变成42 == 42
- "拆封"封装对象如(new String("abc")), 返回其中的基本类型"abc"。 == 中的ToPrimitive强制类型转换也会发生这样的情况
const a = null;
const b = Object(a);
a == b; // false
a === b; // false
- 有一些值不是这样,原因是==算法中其他优先级更高的规则
const a = null;
const b = Object(a);
a == b; //false
const c = undefined;
const d = Object(c);
c == d; // false
const e = NaN;
const f = Object(e);
e == f; // false
// 因为没有对象的封装对象,所以null和undefined不能被封装,Object(null)和Object()均返回一个常规对象
// NaN能够封装为数字类型对象,但拆封后NaN!=NaN
- 比较少见的情况
- 返回其他数字
Number.prototype.valueOf = function() {
return 3;
}
new Number(2) == 3; // true
// 2 == 3不会有这种问题,而Number(2)涉及ToPrimitive转换
- 如果让 a == 2 && a == 3同时成立
let i = 2;
Number.prototype.valueOf = function() {
return i++;
}
let a = new Number(454);
if (a == 2 && a == 3) {
console.log("good!"); // good
}
- 假值的相等比较(容易造成混乱的情况)
console.log("0" == false); // true
console.log(0 == false); // true
console.log([] == false); // true
console.log("" == false); // true
console.log(0 == ""); // true
console.log(0 == []); // true
console.log("" == []); // true
// 极端情况
[] == ![] // true
// 首先根据ToBoolean规则,进行值的显示类型转换,所以[] == ![]变成了[] == false
数组进行ToPrimitive是会转化为字符,[null]会直接转化为""
2 == [2]; //true
"" == [null]; //true
0 == "\n"; //true
-
安全运用隐式类型转换
(1) 如果两边的值其中有true或者false,千万不要使用== (2) 如果两边值中有[],"",或者0,尽量不要使用==
-
抽象关系比较
const a = ["123"];
const b = ["21"];
console.log(a < b); // true
const c = ["123"];
const d = 21;
console.log(c < d); // false
// 比较双方首先调用ToPrimitive,结果如果出现非字符串,就根据ToNumber规则将双方转化为数字进行比较,如果都是字符串,就从头比较字符编码。
const a = {b:42}
const b = {b:43}
// 因为a转化为字符串是[object Object] b也是[object Object]
console.log(a<b); //false
console.log(a==b); //false
console.log(a>b); //false
// 下面这两个情况就很特殊了
console.log(a>=b); //true
console.log(a<=b); // true
// 为true的原因是在JavaScript中<=应该是不大于的意思,>=是不小于的意思
// a<=b处理为 !(a>b) 同理a>=b处理为 !(a<b>)