菜单

类型强制转换系统

相关源文件

目的与范围

本文档提供了 JavaScript 类型强制转换系统的技术概述,该系统在“You Don't Know JS Yet”代码库中实现。类型强制转换是指在 JavaScript 中将一个值从一种类型转换为另一种类型的过程。本文档涵盖了显式和隐式强制转换机制、ECMAScript 规范中定义了控制强制转换的抽象操作,以及在 JavaScript 代码中激活这些操作的具体表达式。有关利用强制转换的相等性比较信息,请参阅相等性比较

来源: types-grammar/ch4.md8-19

类型强制转换:概述

当一个值从一种类型转换为另一种类型时,就会发生类型强制转换。在 JavaScript 中,强制转换是该语言类型系统的基本方面,代表了 JavaScript 的三大支柱之一(与作用域/闭包和原型并列)。

JavaScript 中有两类强制转换

  1. 显式强制转换:当代码直接且有意地将一种类型转换为另一种类型时
  2. 隐式强制转换:当类型转换作为某些其他操作的副作用发生时

显式强制转换和隐式强制转换之间的区别在某种程度上是主观的,并且可能取决于上下文。

来源: types-grammar/ch4.md12-38

抽象操作

JavaScript 规范定义了几个“抽象操作”,它们规定了类型如何转换。这些是概念性机制,不能直接在代码中作为函数调用,但可以通过各种 JavaScript 表达式和语句激活。

核心抽象操作

来源: types-grammar/ch4.md40-47 types-grammar/ch4.md87-105 types-grammar/ch4.md106-126 types-grammar/ch4.md165-187

ToBoolean

ToBoolean 抽象操作将值转换为布尔值。所有 JavaScript 值都分为真值(转换为 true)或假值(转换为 false)。

假值的完整列表

类型
未定义未定义
nullnull
false布尔值
+0, -0, 0数字
0nbigint
NaN数字
"" (空字符串)字符串

所有其他值都被认为是真值并转换为 true

来源: types-grammar/ch4.md48-83

ToPrimitive

ToPrimitive 抽象操作将对象转换为原始值。它接受一个 hint 参数,该参数会影响转换过程。

  1. hint 为“string”时
    • 首先尝试调用对象的 toString() 方法
    • 如果这没有返回原始值,则尝试 valueOf() 方法
  2. hint 为“number”(或没有提示)时
    • 首先尝试调用对象的 valueOf() 方法
    • 如果这没有返回原始值,则尝试 toString() 方法

如果两种方法都不能生成原始值,则会抛出 TypeError

来源: types-grammar/ch4.md87-104

ToString

ToString 抽象操作将值转换为字符串表示

值类型结果示例
未定义"undefined"
null"null"
布尔值"true""false"
数字"42""Infinity""NaN"
-0"0"(注意:负号丢失)
bigint"42"(不带 n 后缀)
symbolTypeError(无法隐式转换)
对象委托给 ToPrimitive,提示为“string”

来源: types-grammar/ch4.md106-162

ToNumber

ToNumber 抽象操作将值转换为数字

值类型结果示例
未定义NaN
null0
布尔值true1false0
字符串解析后的数值或 NaN(如果无效)
空字符串0
仅空白符0
symbolTypeError
bigintTypeError
对象委托给 ToPrimitive,提示为“number”

来源: types-grammar/ch4.md165-254

附加的数值转换操作

有几种专门的数值转换操作

  • ToNumeric()
  • ToIntegerOrInfinity()
  • ToInt32()ToUint32()ToInt16()ToUint16()ToInt8()ToUint8()ToUint8Clamp()
  • ToBigInt()StringToBigInt()ToBigInt64()ToBigUint64()

来源: types-grammar/ch4.md216-237

相等性比较操作

JavaScript 有多种用于比较相等性的抽象操作

SameValue 和 SameValueZero

SameValue() 确定两个值是否完全相同,没有任何例外

  • NaN 视为与其自身相等
  • 区分 0-0

SameValueZero() 类似但认为 0-0 相同。

IsStrictlyEqual 和 IsLooselyEqual

IsStrictlyEqual()(由 === 激活)

  • 如果值类型不同则返回 false
  • 委托给匹配类型的专门比较
  • NaN-0 有特殊处理

IsLooselyEqual()(由 == 激活)

  • 如果类型匹配则委托给 IsStrictlyEqual()
  • 否则执行强制相等性比较,有几个步骤
    1. nullundefined 视为彼此相等
    2. 与数字比较时将字符串强制转换为数字
    3. 与 bigint 比较时将字符串强制转换为 bigint
    4. 将布尔值强制转换为数字
    5. 使用 ToPrimitive() 将对象强制转换为原始值

来源: types-grammar/ch4.md257-349

关系比较

IsLessThan() 抽象操作处理关系比较(<><=>=

  • 接受操作数和评估顺序的参数
  • 在比较前将值强制转换为相同类型
  • 对于字符串:执行词典比较
  • 对于数字:执行数值比较
  • 对于类型不匹配:通常优先进行数值比较

来源: types-grammar/ch4.md352-412

具体强制转换方法

抽象操作由 JavaScript 代码中的具体表达式和语句激活。

转换为布尔值的强制转换

来源: types-grammar/ch4.md419-494

显式布尔值转换

显式地将值转换为布尔值,使用

  1. Boolean(value) 函数(不带 new
  2. 双重否定:!!value

隐式布尔值转换

布尔值强制转换隐式发生在

  1. 条件语句(ifforwhile
  2. 三元表达式(condition ? value1 : value2
  3. 逻辑运算符(&&||)的左操作数

来源: types-grammar/ch4.md424-492

转换为字符串的强制转换

来源: types-grammar/ch4.md497-574

显式字符串转换

显式地将值转换为字符串,使用

  1. String(value) 函数(不带 new
  2. value.toString() 方法(原始值的自动装箱)

隐式字符串转换

字符串强制转换隐式发生在

  1. 字符串连接:value + """" + value
  2. 模板字面量插值:`${value}`

来源: types-grammar/ch4.md498-573

转换为数字的强制转换

来源: types-grammar/ch1.md582-615 types-grammar/ch4.md575-700

显式数字转换

显式地将值转换为数字,使用

  1. Number(value) 函数(不带 new
  2. 一元加号:+value
  3. parseInt(string, radix) 用于整数解析
  4. parseFloat(string) 用于浮点数解析

解析与强制转换的区别

  • 解析(parseInt/parseFloat):从字符串开头提取数字字符,遇到非数字字符停止
  • 强制转换(Number/+):要求整个字符串都是有效的数字格式

来源: types-grammar/ch1.md582-615 types-grammar/ch4.md575-700

转换为对象的强制转换

将值转换为对象,使用

  1. Object(value) 函数
  2. 构造函数调用:new String(value)new Number(value)

来源: types-grammar/ch3.md114-147

类型强制转换的特殊情况

JavaScript 强制转换系统的几个方面特别值得注意或出乎意料

  1. 空字符串 → 数字"" 强制转换为 0,而不是 NaN
  2. Symbol 强制转换限制:Symbol 可以显式转换为字符串(String(sym)),但不能隐式转换(sym + "" 会抛出错误)
  3. NaN 比较NaN === NaNfalse,但 Object.is(NaN, NaN)true
  4. -0 字符串转换-0 强制转换为字符串 "0",而不是 "-0"
  5. 布尔值 → 数字true 变为 1false 变为 0
  6. null 和 undefined:它们彼此强制相等(null == undefinedtrue

来源: types-grammar/ch4.md197-203 types-grammar/ch4.md516-517 types-grammar/ch4.md319-324 types-grammar/ch4.md132-138 types-grammar/ch4.md187-190 types-grammar/ch4.md332

装箱和自动装箱

自动装箱是当访问属性或方法时,原始值隐式转换为其对象包装形式的过程。

这种机制允许原始值“借用”其构造函数的原型方法

基本类型对象包装器原型
字符串字符串String.prototype
数字数字Number.prototype
布尔值布尔值Boolean.prototype
symbol符号Symbol.prototype
bigintBigIntBigInt.prototype

原始值临时包装在其相应的对象包装器中,允许在丢弃包装器之前访问原型方法。

来源: types-grammar/ch2.md98-101 types-grammar/ch3.md114-146

运算符中的强制转换

不同的 JavaScript 运算符会触发不同的强制转换模式

运算符强制转换模式
+如果任一操作数为字符串则进行字符串连接,否则进行数值加法
-, *, /, %两个操作数都进行数值转换
<, >, <=, >=如果操作数并非都为字符串则进行数值比较,否则进行词典字符串比较
==, !=如果类型不同则进行类型强制转换,遵循特定规则
===, !==无强制转换,严格相等检查
&&, `

来源: types-grammar/ch2.md511-542 types-grammar/ch4.md471-483

强制转换路径总结

来源: types-grammar/ch4.md42-254

类型强制转换是 JavaScript 类型系统的一个基本方面,它允许值通过显式转换或隐式操作在不同类型之间进行转换。理解各种强制转换路径及其行为对于编写可预测的 JavaScript 代码至关重要。