数据类型转换
这一节的内容完全是写给面试看的,因为这一块的东西可以算是js不好的一部分,但是偏偏很多公司喜欢把这些东西当面试题来考别人,美其名曰考察其对js了解程度。【冷笑】。如果真有人在生产环境中写出像这样的代码,那么估计水平也就那样。话不多说,就当是为了应付面试,自己也再熟悉一下js的令人头秃的类型转换问题吧。
使用转换函数
Number()
Number(数字) ==> 数字Number(true) ==> 1,Number(false) ==> 0Number(null) ==> 0Number(undefined) ==> NaNNumber(对象)则先调用对象的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: ()=>''}) // 0toString() 和 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)返回falseBoolean(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]"。