前言
前阵子,在实习时,看到公司代码通过在字符串前添加一个加号,完成字符串类型转换为数字类型。比如+'123',输出为数字123。后面查阅相关资料,发现原来是Js的隐式类型转换。
+号运算规则
- 当一侧为
String类型,被识别为字符串拼接,并会优先将另一侧转换为字符串类型。 - 当一侧为
Number类型,另一侧为原始类型,则将原始类型转换为Number类型。 - 当一侧为
Number类型,另一侧为引用类型,将引用类型和Number类型转换成字符串后拼接。 - 如果
+xxx这种形式,会把xxx转化为number类型。比如+{}=NaN。
console.log(3+true) // 4 true转化为1
console.log(3+'4') //34 3转化为字符串
console.log(3+{}) //3[Object Object]
console.log(3+[]) //3(string类型) []转化为""
console.log(+[]) // 0
console.log(+'123b') // NaN
特例
/*
原因:
这里的{a: 3}会被浏览器认为是区块语句而不是对象字面量,
即不认为是个对象,即对应了上面的第四点。
{a: 3}+['3']相当于+['3']
+['3']会进行toPrimitive操作转化为'3'(toPrimitive操作下面会说到)
'3'转化为number类型
最终得到number类型的3
*/
console.log({a: 3}+['3']) // 3(number类型)
const b = {a: 3}
console.log(b+['3']) // [Object Object]3
除乘减运算规则
两个操作数都需要转化为number类型。
console.log('4'/'2') // 2
console.log(['4']/'2') // 2
console.log(2/{})// NaN
console.log(null-3)// -3 null会转化为0
==转换规则
- 对于
number和string比较,将字符串转换为number类型后再进行比较; - 对于
boolean和其他类型的比较,将其boolean类型转换为number类型后再进行比较; - 对于引用类型和原始类型的比较,将对象进行
ToPrimitive操作后再进行比较; - 引用类型之间的比较,判断是否指向同一个地址。
// 建议看了下面ToPrimitive转换规则再回来看
// ![]为false false转化为0(规则2) []转化为0(规则1)
console.log([] == ![]) //true
// false转化为0(规则2) [undefined]通过toString变成''(规则3) ''变为0(规则1)
console.log([undefined] == false)// true
// 规则4
console.log({} == {}) // false
引用类型转换原始值--ToPrimitive
ToPrimitive
ToPrimitive操作就是将引用类型转换为原始值。
// input是调用对象,PreferredType为期待返回的结果类型
ToPrimitive(input, PreferredType)
执行过程
- 如果
input不是引用类型,直接返回结果; - 根据
PreferredType定义hint值;- 如果
PreferredType为number,hint为number; - 如果
PreferredType为string,hint为string; - 其他,
hint为defualt。
- 如果
- 判断
input是否有Symbol.toPrimitive方法,如果有则根据hint的值执行得到对应的结果,否则抛出TypeError错误。
代码来源:Symbol.toPrimitive - JavaScript | MDN (mozilla.org)
// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果。
const obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果。
const obj2 = {
[Symbol.toPrimitive](hint) {
if (hint === "number") {
return 10;
}
if (hint === "string") {
return "hello";
}
return true;
},
};
console.log(+obj2); // 10 — hint 参数值是 "number"
console.log(`${obj2}`); // "hello" — hint 参数值是 "string"
console.log(obj2 + ""); // "true" — hint 参数值是 "default"
- 如果
hint为default,则改为number。也就是说默认是按number。除了Date对象,和Symbol对象。Date对象转换时hint参数是String。Symbol对象进行类型转换会抛出异常; - 执行
OrdinaryToPrimitive运算。- 如果hint是'string',调用toString方法,得到的是原始数据类型,返回该值;否则调用valueOf方法,如果得到的是原始数据类型,返回该值;否则抛出异常;
- 如果hint是'number',则相反;先调用valueOf方法,得到的是原始数据类型,返回该值;否则调用toString方法,如果得到的是原始数据类型,返回该值;否则抛出异常。
valueOf 与 toString 返回值
| 类型 | valueOf | toString |
|---|---|---|
| Object | 对象本身 | [object type] type指的是对象本身的类型识别 |
| Array | 对象本身 | 与join(',')方法返回值一致 |
| Number | 对象本身 | 字符串值,可传入一个参数,决定其进制 |
| String | 对象本身 | 对象本身 |
| Boolean | 对象本身 | 返回"true"或"false"字符串 |
转换表
最后附上转换表~
总结
严格等于(===)万岁!!!