JS 数据类型转换专题
一、转布尔值
1、强制转换之 Boolean(x)
强制转为布尔值,只有空字符串 ""
、null
、undefined
、+0
、-0
和 NaN
转为 false,其他都是 true(包括空数组
、空对象
、new Boolean(false)
...等等)
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean(1) // true
Boolean('s') // true
Boolean([]) // true
Boolean({}) // true
Boolean(new Boolean(false)) // true
2、强制转换之 !! + x
这是转布尔值最便捷的方式,转换规则与 Boolean(x) 一样。
!!'' // false
!!null // false
!!undefined // false
!!0 // false
!!NaN // false
!!1 // true
!!'s' // true
!![] // true
!!{} // true
!!new Boolean(false) // true
3、隐式转换之 if(x)
JS if 语句的条件部分会将非布尔值的参数自动转为布尔值,及条件部分会自动调用 Boolean 函数。
if ('abc') {
console.log('hello')
}
// "hello"
二、转字符串
1、强制转换之 toString()
强制转为字符串(不改变原变量)
注意:null
和 undefined
没有 toString,直接调用会报错。
var a = 123
a.toString() // "123"
var b = true
b.toString() // "true"
var c = {}
c.toString() // "[object Object]"
var d = null;
d.toString() // 报错
var e = undefined
e.toString() // 报错
扩展:toString() 的基模式
Number 类型使用 toString() 时可以传入“基”(二进制的基是 2,八进制的基是 8,十六进制的基是 16)作为参数,并以对应的“基”输出数字。
var i = 10;
i.toString(2); // "1010"
i.toString(8); // "12"
i.toString(16); // "A"
2、强制转换之 String(x)
String(x) 可以转换所有类型为字符串,对于 null
和 undefined
会直接转换为 "null" 和 "undefined",对于对象会返回一个类型字符串,对于数组会返回该数组的字符串形式。
String(1) // "1"
String(true) // "true"
String(null) // "null"
String(undefined) // "undefined"
String({ a: 1 }) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
3、隐式转换之 x+空字符串
这是转字符串最便捷的方法,即加上一个空字符串就可以快速将其他类型转换成字符串。
1 + '' // "1"
'' + true // "true"
'' + null // "null"
'' + undefined // "undefined"
'' + {} // "[object Object]"
'' + [] // ""
'' + function (){} // "function (){}"
三、转数字
1、强制转换之 Number(x)
1-1、对基本类型使用 Number
- 纯数字的字符串(包括
.
开头的数字字符串),转为数字。 - 含非数字的字符串或
undefined
,返回NaN
。 null
、false
、空字符串、空格,转为0
。true
,转为1
。- 负的十六进制、0 开头的八进制,转为十进制。
Number('324') // 324
Number('.32') // 0.32
Number('324abc') // NaN
Number(undefined) // NaN
Number(null) // 0
Number(false) // 0
Number('') // 0
Number(' ') // 0
Number(true) // 1
Number(3.15); // 3.15
Number(023); // 19
Number(0x12); // 18
Number(-0x12); // -18
1-2、对引用类型使用 Number
数组:
- 空数组,转为
0
。 - 单个值为数字、单个值为数字字符串,转为数字。
- 单个值为非数字的字符串,返回
NaN
。 - 多个值,返回
NaN
。
对象、函数,返回 NaN
。
Number([]) // 0
Number([1]) // 1
Number(['1']) // 1
Number(['a']) // NaN
Number([1, 2]) // NaN
Number({ a: 1 }) // NaN
Number(() => (1)) // NaN
2、强制转换之 parseInt(x, 10)
2-1、对基本类型使用 parseInt
与 Number() 的相同点:
- 纯数字的字符串,转为数字。
undefined
,返回NaN
。true
,转为1
。- 负的十六进制、0 开头的八进制,转为十进制。
与 Number() 的不同点:
- 对
.
开头的数字字符串(例如 '.32'),Number() 转为0.32
,而 parseInt 转为NaN
。 - 对含非数字的字符串,Number() 均返回
NaN
,而 parseInt 如果以数字开头,则转为该数字,否则才返回NaN
。 null
、false
、空字符串、空格,Number() 转为0
,而 parseInt 转为NaN
。
parseInt('324') // 324
parseInt('.32') // NaN
parseInt('324abc') // 324
parseInt(undefined) // NaN
parseInt(null) // NaN
parseInt(false) // NaN
parseInt('') // NaN
parseInt(' ') // NaN
parseInt(true) // NaN
parseInt(3.15); // 3
parseInt(023); // 19
parseInt(0x12); // 18
parseInt(-0x12); // -18
2-2、对引用类型使用 parseInt
与 Number() 的相同点:
- 数组单个值为数字、单个值为数字字符串,转为数字。
- 数组单个值为非数字的字符串,返回
NaN
。 - 对象、函数,返回
NaN
。
与 Number() 的不同点:
- 空数组,Number() 转为
0
,而 parseInt 返回NaN
。 - 数组多个值时,Number() 返回
NaN
,而 parseInt 先判断数组第一个值是否为数字或非.
开头的数字字符串,是的话则转为这个数字。
parseInt([]) // NaN
parseInt([1]) // 1
parseInt(['1']) // 1
parseInt(['a']) // NaN
parseInt([1, 2]) // 1
parseInt(['1', 2]) // 1
parseInt(['.1', 2]) // NaN
parseInt({ a: 1 }) // NaN
parseInt(() => (1)) // NaN
扩展:可使用 radix 返回指定基数
parseInt() 的第二个参数表示 radix,用来指定返回的基数,取值范围为 2~36 之间。
如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。
parseInt('123', 5) // 将'123'看作 5 进制数,返回十进制数 38 => 1*5^2 + 2*5^1 + 3*5^0 = 38
parseInt("0xF", 16); // 15
parseInt("F", 16); // 15
parseInt(15.99, 10); // 15
parseInt("15,123", 10); // 15
parseInt("FXX123", 16); // 15
parseInt("15 * 3", 10); // 15
parseInt("15e2", 10); // 15
parseInt("15px", 10); // 15
parseInt("1111", 2); // 15
parseInt("Hello", 8); // NaN
parseInt("546", 2); // NaN(除了“0、1”外,其它数字都不是有效二进制数字)
[1, 2, 3].map(parseInt) // [1, NaN, NaN]
3、强制转换之 parseFloat(x)
3-1、对基本类型使用 parseFloat
基本类型 | Number() | parseInt() | parseFloat() |
---|---|---|---|
'.32' | 0.32 | NaN | 0.32 |
'1.2.3abc' | NaN | 1 | 1.2 |
'' | 0 | NaN | NaN |
' ' | 0 | NaN | NaN |
null | 0 | NaN | NaN |
false | 0 | NaN | NaN |
true | 1 | NaN | NaN |
parseFloat('324') // 324
parseFloat('.32') // 0.32
parseFloat('1.2.3ab') // 1.2
parseFloat(undefined) // NaN
parseFloat('') // NaN
parseFloat(' ') // NaN
parseFloat(null) // NaN
parseFloat(false) // NaN
parseFloat(true) // NaN
parseFloat(3.15); // 3.15
parseFloat(023); // 19
parseFloat(0x12); // 18
parseFloat(-0x12); // -18
3-2、对引用类型使用 parseFloat
引用类型 | Number() | parseInt() | parseFloat() |
---|---|---|---|
[] | 0 | NaN | NaN |
[1, 2] | NaN | 1 | 1 |
['1.2', 2] | NaN | 1 | 1.2 |
['.2', 2] | NaN | NaN | 0.2 |
parseFloat([]) // NaN
parseFloat([1.2]) // 1.2
parseFloat(['1.2']) // 1.2
parseFloat(['a']) // NaN
parseFloat([1.2, 2]) // 1.2
parseFloat(['1.2', 2]) // 1.2
parseFloat(['.2', 2]) // 0.2
parseFloat({ a: 1 }) // NaN
parseFloat(() => (1)) // NaN
4、隐式转换之 +
字符串前面加上 + 即可转为数字,转换规则与 Number() 相同。
// 字符串
+ '' // 0
+ '.32' // 0.32
+ '1a' // NaN
// 布尔值
+ true // 1
+ false // 0
// null
+ null // 0
// undefined
+ undefined // NaN
// 数组
+ [] // 0
+ ['1'] // 1
+ ['1a'] // NaN
// 对象
+ {} // NaN
// NaN
+ NaN // NaN
5、隐式转换之 *
字符串 *1 即可转为数字,转换规则与 Number() 相同。
// 字符串
'' * 1 // 0
'.32' * 1 // 0.32
'1a' * 1 // NaN
// 布尔值
true * 1 // 1
false * 1 // 0
// null
null * 1 // 0
// undefined
undefined * 1 // NaN
// 数组
[] * 1 // 0
['1'] * 1 // 1
['1a'] * 1 // NaN
// 对象
{} * 1 // 无结果
// NaN
NaN // NaN
6、隐式转换之 -
使用 - 可以快速转为数字,转换规则与 Number() 相同。
// 字符串
'1' - 0 // 1
'1' - 1 // 0
'a' - 0 // NaN
'1a' - 0 // NaN
// 布尔值
true - 0 // 1
false - 0 // 0
true - 1 // 0
false - 1 // -1
- true // -1
- false // -0
// null
null - 0 // 0
null - 1 // -1
- null // 0
// undefined
undefined - 0 // NaN
- undefined // NaN
// 数组
[] - 0 // 0
- [] // -0
['1'] - 0 // 1
['1a'] - 0 // NaN
// 对象
{} - 0 // 0
- {} // NaN
// NaN
NaN - 0 // NaN
7、隐式转换之 /
使用 / 可以快速转为数字,转换规则与 Number() 相同。
// 字符串
'1' / 1 // 1
'1' / '1' // 1
'1a' / '1' // NaN
'1' / 0 // Infinity
'0' / 0 // NaN
'1' / '' // Infinity
'0' / '' // NaN
// 布尔值
true / '1' // 1
true / 0 // Infinity
true / '' // Infinity
false / '1' // 0
false / 0 // NaN
false / '' // NaN
// null
null / 1 // 0
null / 0 // NaN
null / '' // NaN
// undefined
undefined / 1 // 0
undefined / 0 // NaN
undefined / ''// NaN
// 数组
[] / 1 // 0
['1'] / 1 // 1
['1a'] / 1 // NaN
// 对象
{} / 1 // 无结果
// NaN
NaN / 1 // NaN
四、== 和 ===
对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换,流程如下:
- 首先判断两者类型是否相同,相同就直接比大小。
- 类型不同的话则进行类型转换。
- 如果在对比 null 和 undefined,则返回 true。
- 通过在对比 string 和 number,则将字符串转换为 number。
1 == '1'
↓
1 == 1
- 如果一方为 boolean,则将 boolean 转为 number 再进行判断。
'1' == true
↓
'1' == 1
↓
1 == 1
- 如果一方为 object 且另一方为 string、number 或者 symbol,则将 object 转为原始类型再进行判断。
'1' == { name: 'Tim' }
↓
'1' == '[object Object]'
而对于 === 来说就简单多了,直接判断两者类型和值是否相同。
五、易混场景
'true' == true
'true' == true // false
// ==> NaN == 1
// ==> false
'false' == false
'false' == false // false
// ==> NaN == 0
// ==> false
== 运算符执行 number 类型转换,'true' 转换为 NaN, boolean 类型 true 转换为 1
null == ''
null == '' // false
null 不等于任何值除了 null 和 undefined
!!"false" == !!"true"
!!"false" == !!"true" // true
// ==> true == true
// ==> true
!! 运算符将字符串 'true' 和 'false' 转为 boolean 类型 true, 因为不是空字符串,然后两边都是 boolean 型不在执行隐式转换操作。
['x'] == 'x'
['x'] == 'x' // true
== 运算符对数组类型执行 number 转换,先调用对象的 valueOf() 方法,结果是数组本身,不是原始类型值,所以执行对象的 toString() 方法,得到字符串 'x'。
[1, 2, 3] == [1, 2, 3]
[1, 2, 3] == [1, 2, 3] // false
当运算符两边类型相同时,不会执行类型转换,两个数组的内存地址不一样,所以返回 false。
true + false
true + false // 1
+
运算符会触发 number 类型转换,因此上面转为 1 + 0。
[1] > null
[1] > null // true
// ==> '1' > 0
// ==> 1 > 0
// ==> true
比较运算符 > 执行 number 类型隐式转换。
"foo" + + "bar"
"foo" + + "bar" // "fooNaN"
// ==> "foo" + (+"bar")
// ==> "foo" + NaN
// ==> "fooNaN"
一元 + 运算符比二元 + 运算符具有更高的优先级。所以 + bar 表达式先求值。一元加号执行字符串 bar 的 number 类型转换。因为字符串不代表一个有效的数字,所以结果是 NaN。在第二步中,计算表达式 'foo' + NaN。
0 || "0" && {}
0 || "0" && {} // {}
// ==> (0 || '0') && {}
// ==> (false || true) && true
// ==> true && true
// ==> true
逻辑运算符 || 和 && 将值转为 boolean 型,但是会返回原始值(不是 boolean)
{} + [] + {} + [1]
{} + [] + {} + [1] // '0[object Object]1'
// ==> +[] + {} + [1]
// ==> 0 + {} + [1]
// ==> 0 + '[object Object]' + '1'
// ==> '0[object Object]1'
所有的操作数都不是原始类型,所以会按照从左到右的顺序执行 number 类型的隐式转换,object 和 array 类型的 valueOf() 方法返回它们本身,所以直接忽略,执行 toString() 方法。 这里的技巧是,第一个 {} 不被视为 object,而是块声明语句,因此它被忽略。计算从 +[] 表达式开始,该表达式通过 toString() 方法转换为空字符串,然后转换为 0
! + [] + [] + ![]
! + [] + [] + ![] // 'truefalse'
// ==> !(+[]) + [] + (![])
// ==> !0 + [] + false
// ==> true + [] + false
// ==> true + '' + false
// ==> 'truefalse'
一元运算符优先执行,+[] 转为 number 类型 0,![] 转为 boolean 型 false。
new Date(0) - 0
new Date(0) - 0 // 0
// ==> 0 - 0
// ==> 0
'-' 运算符执行 number 类型隐式转换对于 Date 型的值,Date.valueOf() 返回到毫秒的时间戳。
new Date(0) + 0
new Date(0) + 0 // 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0'
// ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)' + 0
// ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0'
'+' 运算符触发默认转换,因此使用 toString() 方法,而不是 valueOf()。
六、实现类型判断函数
function getType(value) {
// 判断数据是 null 的情况
if (value === null) {
return value + "";
}
// 判断数据是引用类型的情况
if (typeof value === "object") {
let valueClass = Object.prototype.toString.call(value),
type = valueClass.split(" ")[1].split("");
type.pop();
return type.join("").toLowerCase();
} else {
// 判断数据是基本数据类型的情况和函数的情况
return typeof value;
}
}