谈谈JavaScript中的类型转换机制

45 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

一、概述

JS中有六种简单数据类型:undefinednullbooleanstringnumbersymbol,以及引用类型: object

但是我们在声明的时候只有一种数据类型,到运行期间才会确定当前类型

let a = b ? b : 0

上面的代码, a的值在编译阶段是无法获取的,只有等到程序运行时才能知道

虽然变量的类型是不确定的,但是各个运算符对数据是有要求的,如果运算中的类型与预期不符合,就会发生类型转换机制

常见的类型转换有:

  • 强制转换(显式转换)
  • 自动转换(隐式转换)

显式类型转换

显式转换,顾名思义就是我们很清楚的看到类型的转变,常见的方法有:

  • Number()
  • parseInt()
  • String()
  • Boolean()

Number()

将任意类型的值转为数字类型

转换规则:

初始值转换结果
undefinedNaN
null0
true1
false0
string根据语法和转换规则来转换
SymbolThrow a TypeError exception
Object先调用toPrimitive,在调用toNumber

实践一下:

function log(arg) {
  console.log(arg);
}

log(Number(undefined)); // NaN
log(Number(null)); // 0

// boolean
log(Number(true)); // 1
log(Number(false)); // 0

// string 只要包含一个非数字则转换成NaN
log(Number("abc123")); // NaN
log(Number("123abc")); // NaN
log(Number("abc")); // NaN
log(Number("123")); // 123
log(Number("")); // 0

// object 通常转换成NaN 除了单个数字的数组
log(Number([1, 2, 3])); // NaN
log(Number([100])); // 100
log(Number(["100"])); // 100
log(Number({ a: 1 })); // NaN

从上面可以看出,转换object的时候一般只有一个元素是可以转换为Number类型,其他的转为NaN,字符串只要包含一个非数字的,整个字符串就会被转为NaN

parseInnt()

parseInt()相比Number()要稍微宽松一些,parseInt()函数逐个解析字符,遇到不能转换的就停下来

function log(arg) {
  console.log(arg);
}

log(parseInt(undefined)); // NaN
log(parseInt(null)); // NaN

// boolean
log(parseInt(true)); // NaN
log(parseInt(false)); // NaN

// string 遇到不能转换的则停下来
log(parseInt("abc123")); // NaN
log(parseInt("123abc")); // 123
log(parseInt("abc")); // NaN
log(parseInt("123")); // 123
log(parseInt("")); // NaN

// object 遇到不能转换的就停止转换
log(parseInt([1, 2, 3])); // 1
log(parseInt([100])); // 100
log(parseInt(["100"])); // 100
log(parseInt({ a: 1 })); // NaN

String()

可以将任意类型的值转化成字符串

转换规则:

初始值转换结果
undefined'undefined'
null'null'
boolean'true' or 'false'
numbernumber
SymbolThrow a TypeError exception
Object先调用toPrimitive,在调用toString

实践一下:

function log(arg) {
  console.log(arg);
}

log(String(undefined)); // 'undefined'
log(String(null)); // 'null'

// boolean
log(String(true)); // 'true'
log(String(false)); // 'false'

// number
log(String(123)); // '123'

// object
log(String([1, 2, 3])); // '1,2,3'
log(String([100])); // '100'
log(String(["100"])); // '100'
log(String({ a: 1 })); // '[object object]'

需要注意的是数组的转换

Boolean()

可以将任意类型转为布尔类型,转化规则如下:

初始值转换为 true 的值转换为 false 的值
undefined转换为false
null转换为false
number非0数值0和NaN
string非空字符串''(空字符串)
object任意对象null

实践一下:

function log(arg) {
  console.log(arg);
}

log(Boolean(undefined)); // false
log(Boolean(null)); // false

// string
log(Boolean("")); // false
log(Boolean("a")); // true
log(Boolean("0")); // true

// number
log(Boolean(0)); // flase
log(Boolean(NaN)); // flase
log(Boolean(100)); // true

// object
log(Boolean([1, 2, 3])); // true
log(Boolean([])); // true
log(Boolean({ a: 1 })); // true
log(Boolean({})); // true

三、隐式转换

当运算符两边的操作数不是同一类型的时候,有两种情况会发生隐式转换:

  • 比较运算(==!=><)、ifwhile需要布尔值的地方
  • 算术运算 (+-*/$)

隐式转换布尔值

以下几种情况会被隐式转换成 false

  • undefined
  • null
  • false
  • +0
  • 0
  • -0
  • NaN
  • ""

除了上面的几种会被转化成false,其他都被转换成true

自动转换成字符串

预期为字符串的地方,就会将非字符串的值自动转换为字符串

具体规则:先将符合类型的值转为原始类型的值,再将原始类型的值转为字符串

常发生在+运算中,一旦存在字符串,则会进行字符串拼接

function log(arg) {
 console.log(arg);
}

log("8" + false); // 8false
log("8" + true); // 8true
log("8" + undefined); // 8undefined
log("8" + null); // 8null
log("8" + "a"); // 8a
log("8" + []); // 8
log("8" + [1, 2, 3]); // 81,2,3
log("8" + {}); // 8[object Object]
log("8" + { a: 1 }); // 8[object Object]
log("8" + function () {}); // 8function () {}


自动转换成字符串

除了 +有可能把运算转为字符串,其他运算符都会把运算自动转为数值

function log(arg) {
  console.log(arg);
}

log("8" - true); // 7
log("8" - "2"); // 6
log("8" * 2); // 16
log(8 + null); // 8
log(8 + undefined); // NaN
log(8 * []); // 0
log(8 * [1, 2, 3]); // NaN
log(8 * {}); // NaN
log(8 * { a: 1 }); // NaN
log("abc" - 1); // NaN
log(false / "8"); // 0

null 转为数值的时候,值为0undefined转为数值的时候,值为 NaN, 不为空的数组也会转为NaN