上篇文章主要介绍了一下各种数据类型转换成Boolean,Number,String的规则。刻意没有去谈到有关于与运算符相关类型转换。这篇就重点讲一下这方面的知识。
上图
一元运算符 +
一元运算符遵从其他类型转Number规则(ToNumber)。
先判断是不是基本数据类型,如果是
补充Symbol与BigInt
这两种数据类型都不支持隐式类型转换,会报错。
如果是引用数据类型,用ToPtimitive(obj,Number)这个方法。
- 如果对象具有 valueOf 方法,且返回一个原始值,则 JavaScript 将这个原始值转换为数字并返回这个数字
- 否则,如果对象具有
toString方法,且返回一个原始值,则 JavaScript 将其转换并返回。 - 否则,JavaScript 抛出一个类型错误异常
代码实例
console.log(+1); //1
console.log(+"a"); //NaN
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+undefined); // NaN
console.log(+2n); //error
console.log(+Symbol(1));//error
console.log(+[]); //0
console.log(+[2,3,4]); //NaN
console.log(+{}); //NaN
分析一下+[2,3,4]为什么会是NaN.
- 首先数组不是基本数据类型,直接用
ToPtimitive(obj,Number)这个方法。 - [2,3,4]有valueOf方法但是返回的不是原始数据类型,所以用
toString,返回"1,2,3"。 - 将"1,2,3"转换为数字发现有非法字符,报错。
二元运算符 +
当计算value1 + value2时,规则如下
- lprim = ToPrimitive(value1)
- rprim = ToPrimitive(value2)
- 如果 lprim 是字符串或者 rprim 是字符串,那么返回 ToString(lprim) 和 ToString(rprim)的拼接结果
- 否则返回 ToNumber(lprim) 和 ToNumber(rprim)的运算结果
文字比较难理解,我们通过代码举几个例子演示一下。
相同数据类型相加
console.log(1 + 1); //2
console.log("a" + "a"); // "aa"
console.log(true + true); //2
console.log(null + null); //0
console.log(undefined + undefined); //NaN
console.log(Symbol(1) + Symbol(2)); //error
console.log(2n + 3n); //5n
console.log(NaN + NaN); //NaN
console.log({} + {}); // [object Object][object Object]
console.log([] + []); //""
不同类型相加
true(Boolean) + 其他
console.log(true + "a"); // "truea"
console.log(true + true);// 2
console.log(true + false);// 1
console.log(true + null);// 1
console.log(true + undefined);// NaN
console.log(true + Symbol(1));// error
console.log(true + 2n);// error
console.log(true + []); // "true"
console.log(true + [1, 2, 3]); // "true1,2,3"
console.log(true + {}); // "true[object Object] "
"a"(String) + 其他
console.log("a" + "a"); // "aa"
console.log("a" + true); //"atrue"
console.log("a" + false); //"afalse"
console.log("a" + null); // "anull"
console.log("a" + undefined); // "aundefined"
console.log("a" + Symbol(1)); // error
console.log("a" + 2n); // "a2"
console.log("a" + []); // "a"
console.log("a" + [1, 2, 3]); //"a1,2,3 "
console.log("a" + {}); // "a[object Object] "
1(Number) +其他
console.log(1 + "a"); // "1a"
console.log(1 + true); // 2
console.log(1 + false); // 1
console.log(1 + null); // 1
console.log(1 + undefined); //NaN
console.log(1 + Symbol(1)); // error
console.log(1 + 2n);//error
console.log(1 + []); // "1"
console.log(1 + [1, 2, 3]); //"11,2,3"
console.log(1 + {}); // "1[object Object]"
可以看出,这么不同的类型相加,如果仅仅是凭借记忆力去强行记忆的话,很容易就会忘记。
但是我们利用规则来解决这些问题的话,就显得轻而易举了。
这里我们针对一些比较难以理解的输出分析一下。 相同类型相加中的
console.log(undefined + undefined); //NaN
console.log({} + {}); // [object Object][object Object]
console.log([] + []); //""
直接用规则。
undefined + undefined
-
左右两边都属于基本数据类型,所以lprim = undefined, rprim = undefined。
-
两个都不是字符串,所以返回的是ToNumber(lprim) 和 ToNumber(rprim)的运算结果
-
ToNumber(undefined)是什么? 看ToNumber规则发现是NaN
-
NaN + NaN 最终的结果就是NaN
{} + {}
-
{}属于引用数据类型,所以用ToPrimitive(obj,Number)。 -
先使用
{}的valueOf方法,发现返回的不是原始数据类型,于是用toString方法,返回"[object object]",字符串类型。 -
左右两边都是字符串类型,返回 ToString(lprim) 和 ToString(rprim)的拼接结果。
-
"[object object]"+"[object object]"最终的结果就是"[object object][object object]"
[] + []这道美味就留给读者老爷们啦。
另外其他的有关于二元运算符+的类型转换,读者老爷们如果有时间可以试着去做一下。有问题的请在文章下方留言,我会问您解答的,如果我解答不了,我会想办法帮您解答的。
还有一点值得注意的是Symbol类型不能用来运算,从上面的结果也可以看出。BigInt也只能和它自己本身运算。
==相等
说实话,这玩意用于类型转换的规则实在太多了,而且也不是很规范,所以我建议大家还是去使用更加标准以及严格的===运算符。
不过考虑到部分读者可能会有点强迫症,这里也贴一下具体的规则。
"==" 用于比较两个值是否相等,当要比较的两个值类型不一样的时候,就会发生类型的转换。
关于使用"=="进行比较的时候,具体步骤可以查看规范11.9.5:
- 如果类型相同,无须进行类型转换;
- 如果其中一个操作值是
null或者undefined,那么另一个操作符必须为null或者undefined,才会返回true,否则都返回false; - 如果其中一个是
Symbol类型,那么返回false; - 两个操作值如果为
string和 number 类型,那么就会将字符串转换为number; - 如果一个操作值是
boolean,那么转换成number; - 如果一个操作值为
object且另一方为string、number或者symbol,就会把object转为原始类型再进行判断(调用object的valueOf/toString方法进行转换)。
===相等
===判断是否相等相对于==来说简化了太多,具体来说就一条。
左右两边类型与值是否都完全一致,是就返回true,否则返回false。
但是===存在两个bug,这两个bug其实也存在与==中
- === 认为NaN不等于自身,,但是这并不符合人类正常逻辑思维。
- 还有就是 === 认为+0 与 -0 是完全相同的。
console.log(NaN === NaN) // false
console.log(+0 === -0) // true
于是在ES6中,Object新增一个is方法修复了这两个bug。
Object.is()的作用与===类型,也是判断两个变量是否相等,但是它修复了NaN不等于自身以及+0等于-0这两个不符合人类正常逻辑思维的bug。
Object.is(), === 和 == 区别
- 两等号判等,会在比较时进行类型转换。
- 三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false)
- 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 认定为是相等的。
结语
感谢您看到这里