# 数据类型转换

这一节的内容完全是写给面试看的,因为这一块的东西可以算是js不好的一部分,但是偏偏很多公司喜欢把这些东西当面试题来考别人,美其名曰考察其对js了解程度。【冷笑】。如果真有人在生产环境中写出像这样的代码,那么估计水平也就那样。话不多说,就当是为了应付面试,自己也再熟悉一下js的令人头秃的类型转换问题吧。

# 使用转换函数

# Number()

  • Number(数字) ==> 数字
  • Number(true) ==> 1,Number(false) ==> 0
  • Number(null) ==> 0
  • Number(undefined) ==> NaN
  • Number(对象)则先调用对象的valueOf(),然后依次按照上面的规则转换;如果valueOf()返回了NaN,则调用对象的toString()方法,然后依次按照上面的规则转换
  • Number(字符串)
    • 如果字符串只包含数字,则将其转换为十进制数字,忽略前导零
    • 如果字符串只包含浮点数,则将其转为对应的浮点数,忽略前导零
    • 如果字符串包含有效的十六进制字符,比如:0x1f,则将其转为十进制的等值数字
    • 如果是空字符串,返回 0
    • 不满足上面情况的,返回NaN

看几个例子:

Number(true) // 1
Number('23') // 23
Number('0x1f') // 31
Number(null) // 0
Number('') // 0
Number(undefined) // NaN
Number('hello') // NaN
Number({valueOf: ()=>''}) // 0

# toString()String()

几乎每个值都有toString()方法,它可以返回操作数都对于字符串形式的展现。另外,对数字类型进行操作的时候,还可以传入基数来控制返回值的进制。但是它不能在nullundefined身上调用。在你不知道操作数的数据类型的时候,可以使用String()来进行转换,它的规则如下:

  • 操作数有toString()方法的话调用toString()
  • String(undefined) 返回 "undefined"字符串
  • String(null) 返回 "null"字符串

看几个例子:

let num = 10;

num.toString(2); // 1010
num.toString(8); // 12
String(undefined); // "undefined"

# Boolean()

这个函数就相对的简单一些,它的规则也特别简单:

  • Boolean(true) 返回 trueBoolean(false) 返回 false
  • Boolean(undefined) 返回 false
  • 参数是字符串的话,只有空串""的时候才返回false
  • 参数是数字类型的话,只有0NaN才会返回false
  • 参数是对象类型的话,只有null才会返回false

看几个例子:

Boolean({}); // true
Boolean(0); // false
Boolean(''); // false
Boolean(' '); // true

# 一元加和减操作符

这个很简单,对于非数字来说,就是在它的上面调用Number()函数将它转成数字就行了。比如:

+'12'; // 12
+'12hh'; // NaN
+ false; // 0
+ true; // 1
+ ({}); // NaN
+ ({valueOf: () => 12, toString: ()=>1212}); // 12
+ []; // 0。+[] => +"" => Number("") => 0

# 相等操作符

相等运算符包括==(相等)和!=(不相等),当对两个操作数进行相关运算的时候,如果它们的数据类型不同,则会按照如下的规则进行转换:

  • 如果有一个操作数为布尔值,则将其转换为数字进行比较:false => 0, true => 1
  • 如果有一个操作数是数字,另一个是字符串,则将字符串转换为数字再进行比较
  • 如果有一个操作数是对象,则先调用它的valueOf()方法,用得到的基本类型按照前面的规则去比较;如果没有valueOf()方法,则调用它的toString()方法,用得到的基本类型按照前面的规则去比较
  • 如果两个操作数都是对象,则比较它们是否指向同一个对象
  • nullundefined 是相等的,它们不会进行转换
  • NaN 不等于任何操作数

Ok,规则看上去挺简单,我们来看看下面这些有(qi)趣(pa)的例子吧:

false == 0; // true
true == 1; // true
'hello' == 23; // false
'23' == 23; // true
({ valueOf: ()=>12 }) == 12; // true
({ toString: ()=>12 }) == 12; // true
[] == []; // false 因为这是两个不同的对象
[] != []; // true

# 关系操作符

关系操作符包括><>=<=,它连接的两个操作数之间也会发生数据转换,规则如下:

  • 如果两个操作数都是数字,则进行数字大小的比较
  • 如果两个操作数都是字符串,那么比较它们对应位置的字符编码值
  • 如果其中一个是数字,将另一个转为数字进行比较数字大小
  • 如果其中一个是对象,则调用它的valueOf方法,用得到的结果按照前面的规则比较;如果没有valueOf,那么调用toString,用得到的结果按照前面的规则比较
  • 如果其中一个是布尔值,则把它转为数值后按照上面的规则与另一个操作数进行比较

Ok,规则看上去挺简单,我们来看看下面这些有(qi)趣(pa)的例子吧:

23 < 3; // false
'23' < '3'; // true,因为 '2'.charCodeAt(0) == 50,'3'.charCodeAt(0) == 51
'23' < 3; // false
({ valueOf: ()=>'12' }) < 13; //true
({ valueOf: ()=>'12' }) < ({ valueOf: ()=>'13' }); // true
true < 0; // false

# 加性操作符

加性操作符包括+-两个,这里我们讨论数字以外的情况:

  • 如果有一个是字符串,则把另一个转成字符串后操作
  • 两个都是字符串,则进行字符串的拼接
  • 两个都是布尔值的话,进行数字相加:true=>1, false=>0
  • 如果有一个是对象、数字或者布尔值的话,则调用toString()方法获取字符串的值后进行操作

看看例子:

[] + []; // 空字符串
[1,2] + [3,4]; // "1,23,4",因为数组的`toString()`方法就是数组内元素的字符串形式
[{name: 'Jerry'}] + [1,2]; // "[object Object]1,2"。对象的`toString`没定义的话就是[object Object]
{} + []; // 0
true + false;// 1

有一个例子比较特殊,我们重点分析一下:

{} + []; // 0
[] + {}; // "[object Object]"

首先分析{}+[],它为什是0呢?因为在js中,开头的{}会被解释成一个代码块,然后对于剩下的+[]又解释成一元的加性运算,根据上面的规则就得出0。至于下面的就比较简单了,[].toString() 以后就是""{}"[object Object]",加一起就是"[object Object]"

上次更新: 5/23/2020, 3:25:52 PM