JavaScript中不得不学的类型转换(下)

上篇文章主要介绍了一下各种数据类型转换成Boolean,Number,String的规则。刻意没有去谈到有关于与运算符相关类型转换。这篇就重点讲一下这方面的知识。

上图

类型转换下.png

一元运算符 +

一元运算符遵从其他类型转Number规则(ToNumber)。

先判断是不是基本数据类型,如果是

tonumber.png
补充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.

  1. 首先数组不是基本数据类型,直接用ToPtimitive(obj,Number)这个方法。
  2. [2,3,4]有valueOf方法但是返回的不是原始数据类型,所以用toString,返回”1,2,3″。
  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

当执行x == y 时:

两边的类型是否相同,相同的话就比较值的大小,例如1==2,返回false
判断的是否是null和undefined,是的话就返回true
判断的类型是否是String和Number,是的话,把String类型转换成Number,再进行比较
判断其中一方是否是Boolean,是的话就把Boolean转换成Number,再进行比较
如果其中一方为Object,且另一方为String、Number或者Symbol,会将Object转换成字符串,再进行比较

妈呀,太多了。

===相等

===判断是否相等相对于==来说简化了太多,具体来说就一条。

左右两边类型与值是否都完全一致,是就返回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 认定为是相等的。

结语

感谢您看到这里

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享