3

前言

在第一篇文章中,讲解了 关于“==”时,JS做的类型转换。从第一篇文章中可以发现 == 时,基本类型都朝着数字类型转换,还是贴出上篇文章的图:

图片描述

那么JS类型转换都是按照这个模式进行转换的吗?例如null能转换成数字类型吗?如果能,会转换成多少?


       const data = 1 + null;
       data;// 1

你想到这个结果了吗?

正文

基本类型转换

下面是JS类型转换的图表:

图片描述

图表显示null转换成了0。不是说 null 没有 toStringvalueOf 的方法的吗?怎么能转换成数字呢??
图片描述

这完全不符合第一篇 == 的套路啊!

具体怎么回事呢?

问题在于JS类型转换只存在于“==”的时候吗?肯定不是!

除了==符号会产生类型转换,'+' '-' '*' '/' '>''<'等符号也会使JS发生类型转换,所以==的类型转换规则不是万能的,只适用于== 。那么应该如何记住类型转换这张表格呢?其实大部分转换规则是可以根据第一篇文章讲的==的转换规则得出正确答案的,只是有几个特殊的例子罢了。

第一篇文章讲到了 {} 会转换成字符串 [object Object] ,则:

图片描述

比较特殊的就是undefined null类型:

  1. 在进行 == 的时候,undefined null 会尝试转换成基本类型,但是不存在 toString valueOf 方法,所以无论如何是转换不成基本类型的。
  2. 在做字符串拼接的时候会按照表里面的转换成字符串的规则
  3. 在做数值运算的时候会按照表中转换成数字的规则

表格中 {} 转换成字符串类型和数值类型通常如下:

图片描述

String({})// [object Object]
Number({})// NaN

Object类型转换成基本类型

ECMAScript内部有一个函数 ToPrimitive() (这个函数不能在javascript中调用), 下面是转换规则:

ToPrimitive(input, PreferredType?)

这个可选的 PreferredType 表示最终要转换成的基本类型:
它是数字类型或者字符串类型,这取决于ToPrimitive()的结果是否可以转换成一个数字还是一个字符串。
如果PreferredType 是数字类型, 转换将遵循以下步骤:

  1. 如果输入的是基本类型,就直接返回它
  2. 如果输入的是 Object
    (1)会先调用 input.valueOf() 。如果结果是基本类型就返回它
    (2)如果 input.valueOf() 不是基本类型,就会调用 input.toString() ,如果结果是基本类型就返回它
    (3)如果还不能得到基本类型,就会抛出TypeError错误

如果PreferredType 是 String , 第二条的(1)(2)顺序反转一下。

下面看一组转换情况:

Number([9]);// 指定转换方式 ->9
0 + [9];// 默认转换方式->'09'

(4) 如果指定了要转换的类型,则会优先调用转换的方法,例如:

     var s = { toString: function () { return '7'; } }; 
     
     String(s);// toString() => '7'
     Number(s);// valueOf() => 7

Number() 与 parseInt()/parseFloat()

1.Number(num) 会对boolean string null 类型做一些转换:

    parseFloat(true); // same as parseFloat('true') => NaN
    Number(true); // 1
    
    parseFloat(null); // same as parseFloat('null') => NaN
    Number(null); // 0
    
    parseFloat(''); // NaN
    Number(''); // 0

也就是说Number走的是类型转换那张表。
我们经常使用 +[number]的形式来实现Number(number)。

2.parseInt(num,radix)/parseFloat(num,radix)可以设置解析的进制radix,并且会解析出合法的部分:

 parseFloat('123.45#'); // 123.45
 Number('123.45#'); // NaN

parseFloat('\t\v\r12.34\n');

parseInt()/parseFloat()才是真正的解析数字。

3.使用parseInt()去解析数字会有问题

Don’t use parseInt() to convert a number to an integer:coercion to string is an unnecessary detour and even then, the result is not always correct.(《SpeakingJavascript》)

情况一:整数>=21bit之后会用e表示数字大小


     parseInt(1000000000000000000000.5, 10); // 1
     首先转换成字符串:
     String(1000000000000000000000.5); // '1e+21'

情况二:小数部分>=7bit会用e表示数字大小


    parseInt(0.0000008, 10); // 8
    String(0.0000008); // '8e-7' 

总结:
1.大多情况下优先使用Number()
2.如果确定是解析字符串,并且取里面能提取出的数字,这种情况下使用parseInt()/parseFloat()
3.非十进制解析的情况下使用parseInt()/parseFloat()

后记

在做== 运算时:右侧世界undefined null ,永远不等于左侧的世界中的值,是因为undefined null 想转换成基本类型(和引用类型处理方式一致),但是它们没有toString valueOf方法。

这一篇undefined null 类型转换还可以看出:例如 + 运算,JS会根据实现,按照表格中的JS类型转换,{}转换成字符串[object Object],null转换成数字0,数组转字符串类似调用join。


specialCoder
2.1k 声望167 粉丝

前端 设计 摄影 文学