# 数据类型转换
这一节的内容完全是写给面试看的,因为这一块的东西可以算是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()
方法,它可以返回操作数都对于字符串形式的展现。另外,对数字类型进行操作的时候,还可以传入基数来控制返回值的进制。但是它不能在null
和undefined
身上调用。在你不知道操作数的数据类型的时候,可以使用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)
返回true
,Boolean(false)
返回false
Boolean(undefined)
返回false
- 参数是字符串的话,只有空串
""
的时候才返回false
- 参数是数字类型的话,只有
0
和NaN
才会返回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()
方法,用得到的基本类型按照前面的规则去比较 - 如果两个操作数都是对象,则比较它们是否指向同一个对象
null
和undefined
是相等的,它们不会进行转换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]"
。