Skip to main content

JS 数据类型转换专题

一、转布尔值

1、强制转换之 Boolean(x)

强制转为布尔值,只有空字符串 ""nullundefined+0-0NaN 转为 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()

强制转为字符串(不改变原变量)

注意:nullundefined 没有 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) 可以转换所有类型为字符串,对于 nullundefined 会直接转换为 "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
  • nullfalse、空字符串、空格,转为 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
  • nullfalse、空字符串、空格,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.32NaN0.32
'1.2.3abc'NaN11.2
''0NaNNaN
' '0NaNNaN
null0NaNNaN
false0NaNNaN
true1NaNNaN
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()
[]0NaNNaN
[1, 2]NaN11
['1.2', 2]NaN11.2
['.2', 2]NaNNaN0.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;
}
}