Skip to content

类型转换

JavaScript 是弱类型语言,会在运算时自动进行类型转换。理解这些规则,能帮你避开很多坑。

🎯 两种转换方式#

// 显式转换
const num = Number('42') // 42
const str = String(42) // "42"
const bool = Boolean(1) // true
// 隐式转换
const num2 = '42' - 0 // 42
const str2 = 42 + '' // "42"
const bool2 = !!'hello' // true

转为数字#

Number() 函数#

// 字符串
Number('42') // 42
Number('3.14') // 3.14
Number('42px') // NaN(无法完全解析)
Number('') // 0
Number(' ') // 0(空白字符串)
// 布尔值
Number(true) // 1
Number(false) // 0
// null 和 undefined
Number(null) // 0
Number(undefined) // NaN
// 对象
Number({}) // NaN
Number([]) // 0(空数组)
Number([1]) // 1(单元素数组)
Number([1, 2]) // NaN(多元素数组)

parseInt 和 parseFloat#

// parseInt:解析整数
parseInt('42') // 42
parseInt('42.9') // 42(截断小数)
parseInt('42px') // 42(能解析前面的数字)
parseInt('px42') // NaN(开头不是数字)
parseInt(' 42 ') // 42(忽略空白)
// 指定进制
parseInt('ff', 16) // 255
parseInt('1010', 2) // 10
parseInt('077', 8) // 63
// 🔶 不指定进制的坑
parseInt('08') // 8(现代浏览器)
// 旧浏览器可能解析为八进制的 0
// parseFloat:解析浮点数
parseFloat('3.14') // 3.14
parseFloat('3.14.15') // 3.14(到第一个无效字符停止)
parseFloat('314e-2') // 3.14(支持科学计数法)

隐式转数字#

// 一元 + 运算符
;+'42' + // 42
true + // 1
null + // 0
undefined + // NaN
[] + // 0
{} // NaN
// 减法、乘法、除法
'10' - 5 // 5
'10' * 2 // 20
'20' / 4 // 5
// 比较运算符(非相等)
'10' > 5 // true('10' 转为 10)
'10' > '5' // false(字符串比较)

转为字符串#

String() 函数#

String(42) // "42"
String(3.14) // "3.14"
String(true) // "true"
String(false) // "false"
String(null) // "null"
String(undefined) // "undefined"
String([1, 2, 3]) // "1,2,3"
String({ name: 'test' }) // "[object Object]"
String(Symbol('id')) // "Symbol(id)"

toString() 方法#

const num = 42
num.toString() // "42"
num.toString(2) // "101010"(二进制)
num.toString(16) // "2a"(十六进制)
const bool = true
bool.toString() // "true"
const arr = [1, 2, 3]
arr.toString() // "1,2,3"
// 🔶 null 和 undefined 没有 toString 方法
// null.toString() // TypeError
// undefined.toString() // TypeError

隐式转字符串#

// 加号连接
42 + '' // "42"
true + '' // "true"
null +
''[(1, 2)] + // "null"
'' // "1,2"
// 模板字符串
`value: ${42}` // "value: 42"
`value: ${null}` // "value: null"
`value: ${[1, 2]}` // "value: 1,2"

转为布尔值#

Boolean() 函数#

只有 6 个假值,其余都是真值:

// 假值(Falsy)
Boolean(false) // false
Boolean(0) // false
Boolean(-0) // false
Boolean(0n) // false(BigInt 零)
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(NaN) // false
// 真值(Truthy)
Boolean(true) // true
Boolean(1) // true
Boolean(-1) // true
Boolean('0') // true(非空字符串)
Boolean('false') // true(非空字符串)
Boolean([]) // true(空数组)
Boolean({}) // true(空对象)
Boolean(function () {}) // true

隐式转布尔#

// 双重否定
!!'hello' // true
!!0 // false
!!null // false
!![] // true
// 条件语句
if ('hello') console.log('真值')
if (0) console.log('不会执行')
// 逻辑运算
'hello' && 'world' // "world"(都是真值)
'' && 'world' // ""(第一个是假值)
'hello' || 'world' // "hello"(第一个是真值)
'' || 'world' // "world"

对象转原始值#

对象转原始值遵循 ToPrimitive 规则。

转换流程#

// 转数字时的调用顺序:valueOf() → toString()
const obj = {
valueOf() {
console.log('valueOf')
return 42
},
toString() {
console.log('toString')
return 'hello'
},
}
console.log(+obj) // valueOf → 42
console.log(`${obj}`) // toString → "hello"(字符串上下文优先 toString)

自定义转换#

// Symbol.toPrimitive 优先级最高
const obj = {
[Symbol.toPrimitive](hint) {
console.log(`hint: ${hint}`)
if (hint === 'number') return 42
if (hint === 'string') return 'hello'
return true // default
},
}
console.log(+obj) // hint: number → 42
console.log(`${obj}`) // hint: string → "hello"
console.log(obj + '') // hint: default → "true"

常见对象转换#

// 数组
console.log([1, 2, 3] + '') // "1,2,3"
console.log(+[]) // 0([] → "" → 0)
console.log(+[1]) // 1([1] → "1" → 1)
console.log(+[1, 2]) // NaN([1,2] → "1,2" → NaN)
// 对象
console.log({} + '') // "[object Object]"
console.log(+{}) // NaN
// Date 对象特殊:默认转字符串
const date = new Date()
console.log(date + '') // "Tue Dec 03 2025 ..."
console.log(+date) // 1733212800000(时间戳)

相等比较的类型转换#

== 的转换规则#

// 1. 相同类型:直接比��
5 == 5 // true
'hello' == 'hello' // true
// 2. null 和 undefined:相互相等
null == undefined // true
null == null // true
undefined == undefined // true
// 3. 数字和字符串:字符串转数字
5 == '5' // true('5' → 5)
0 == '' // true('' → 0)
// 4. 布尔和其他:布尔先转数字
true == 1 // true(true → 1)
false == 0 // true(false → 0)
true == '1' // true(true → 1,'1' → 1)
;(((false ==
''[// 5. 对象和原始值:对象转原始值 // true(false → 0,'' → 0)
1]) ==
(1)['1']) == // true([1] → "1" → 1)
(1)[(1, 2)]) == // true
'1,2' // true

经典陷阱#

// 让人困惑的相等
console.log([] == false) // true
console.log([] == ![]) // true!
// [] → "" → 0
// ![] → false → 0
// 0 == 0 → true
console.log(null == false) // false(null 只等于 undefined)
console.log(undefined == false) // false
// 更多陷阱
console.log(' \t\n' == 0) // true(空白字符串转为 0)
console.log('0' == false) // true
console.log('0' == 0) // true
console.log(false == 0) // true
// 但是
console.log('0' == false) // true
console.log('0' == '') // false!

加法的类型转换#

加法是最复杂的运算符,规则如下:

// 规则1:有字符串则连接
'hello' + 'world' // "helloworld"
'hello' + 42 // "hello42"
42 + 'hello' // "42hello"
// 规则2:无字符串则转数字相加
true + true // 2
true + false // 1
null + 1 // 1
undefined + 1 // NaN
// 规则3:对象先转原始值
[1, 2] + [3, 4] // "1,23,4"(都转为字符串)
{} + [] // 0({}被解析为空块,+[] = 0)
;({}) + [] // "[object Object]"
[] + {} // "[object Object]"
// 经典题目
console.log(1 + '2' + 3) // "123"
console.log(1 + 2 + '3') // "33"
console.log('1' + 2 + 3) // "123"

实战技巧#

安全的类型转换#

// 转数字
function toNumber(value) {
const num = Number(value)
return Number.isNaN(num) ? 0 : num
}
// 转整数
function toInteger(value) {
return Math.floor(Number(value)) || 0
}
// 转字符串(处理 null/undefined)
function toString(value) {
if (value == null) return ''
return String(value)
}
// 转布尔(明确真假值)
function toBoolean(value) {
return value != null && value !== '' && value !== 0 && value !== false
}

判断空值#

// 判断是否为空(null 或 undefined)
function isNullish(value) {
return value == null // 利用 == 的特性
}
// 判断是否为假值
function isFalsy(value) {
return !value
}
// 判断是否为空白字符串
function isBlank(value) {
return typeof value === 'string' && value.trim() === ''
}
// 判断是否为空对象
function isEmptyObject(obj) {
return Object.keys(obj).length === 0
}
// 判断是否为空数组
function isEmptyArray(arr) {
return Array.isArray(arr) && arr.length === 0
}

默认值处理#

// || 的问题:0 和空字符串被视为假值
function getPort(config) {
return config.port || 3000 // port 为 0 时会返回 3000
}
// ?? 更安全
function getPortSafe(config) {
return config.port ?? 3000 // port 为 0 时返回 0
}
// 复杂默认值
function getConfig(options) {
return {
host: options?.host ?? 'localhost',
port: options?.port ?? 3000,
debug: options?.debug ?? false,
}
}

常见面试题#

🙋 [] == ![] 为什么是 true?#

// 步骤分解:
// 1. ![] 先执行,[] 是真值,![] = false
// 2. [] == false
// 3. [] 转原始值:[].toString() = ""
// 4. "" == false
// 5. 两边转数字:0 == 0
// 6. 结果:true

🙋 + [] 和 [] + 的区别?#

// {} + []
// {} 被解析为空代码块
// +[] 是一元加操作,[] → "" → 0
// 结果:0
// [] + {}
// 这是二元加法
// [] → ""
// {} → "[object Object]"
// 结果:"[object Object]"
// 强制 {} 为表达式
;({}) + [] // "[object Object]"

🙋 如何让 a == 1 && a == 2 && a == 3 为 true?#

// 方案1:自定义 valueOf
const a = {
value: 1,
valueOf() {
return this.value++
},
}
console.log(a == 1 && a == 2 && a == 3) // true
// 方案2:使用 getter
let _a = 1
Object.defineProperty(window, 'a', {
get() {
return _a++
},
})
console.log(a == 1 && a == 2 && a == 3) // true
// 方案3:数组的 join
const b = [1, 2, 3]
b.join = b.shift
console.log(b == 1 && b == 2 && b == 3) // true

总结#

转换目标常用方法隐式触发场景
数字Number() +x算术运算、比较运算
字符串String() ""+ 连接、模板字符串
布尔Boolean() !!条件判断、逻辑运算

核心要点���