jejuin/Blog

ECMAScript 之数据类型转换(上)

Opened this issue · 0 comments

前言

将数据从一种类型转换为另一种类型称为数据类型转换。

数据类型转换分为两种:

  • 显示数据类型转换:直接调用 JS 暴露的 API 进行数据类型转换,如 parseInt,Number() 等
  • 隐式数据类型转换:使用某些运算符或语句时会触发隐式数据类型转换,如 +/- 运算符,if 条件语句等

下面主要介绍了几种数据类型转换的底层算法。

以下算法均为底层 ECMAScript 规范实现,并没有暴露出来。

ToPrimitive ( input [ , PreferredType ] )

将数据类型转换为原始值。

第一个参数 input,表示要处理的输入值。

第二个参数 PreferredType ,非必填,表示希望转换成的类型,有两个值可以选,Number 或者 String。

image

ObjectToPrimitive

对象转为原始类型的本质是:调用内部 [[DefaultValue]] (hint) 方法,返回原始值。其中 hint 为 ToPrimitive 中的第二参数 preferredType。

[[DefaultValue]] (hint) 算法如下:

  • 当没有传入 hint 时,如果对象是 String 或 Date 类型,相当于传入 String,否则,都相当于传入 Number。
  • hint = String:会首先调用 toString 方法,判断是否返回原始值,如果不能返回,再调用 valueOf 方法。如果都不能返回原始值,则抛出运行时错误。
  • hint = Number:会首先调用 valueOf 方法,判断是否返回原始值,如果不能返回,再调用 toString 方法。如果都不能返回原始值,则抛出运行时错误。

ToBoolean

将数据类型转换为布尔类型。底层调用的是 Boolean(input) 方法。

image

ToNumber

将数据类型转换为数字。底层调用的是 Number(input) 方法。

image

其中最为复杂的就是字符串转为数字类型。

StringToNumber

ES3 规范原文:如果不能将字符串解释为 StringNumericLiteral 的扩展,则 StringToNumber 的结果为 NaN。

简单的说,就是如果字符串不符合 StringNumericLiteral 的要求,则不能进行转换。

那么 StringNumericLiteral 包含哪些内容呢?我们来看下。

  • Number 类型的字符串都支持转换:如小数、十进制数、16 进制数(对于 0x 或 0X 开头的字符串会被识别为 16 进制数,对于 0 开头的八进制数不按八进制处理,而是十进制,忽略所有前导 0)、Infinity、NaN等。
console.log(Number('-1')) // -1
console.log(Number('1')) // 1
console.log(Number("Infinity")) // Infinity
console.log(Number("NaN")) // NaN
console.log(Number("1e2")) // 100
console.log(Number(".1")) // 0.1
console.log(Number("00123")) // 123
console.log(Number("-00123")) // -123
console.log(Number("0x11")) // 17
  • StrWhiteSpace + StrWhiteSpaceChar:空格,<TAB><SP><NBSP><FF><VT><CR><LF><LS><PS><USP> 这些内容都会被转换为 0
console.log(Number("")) // 0
console.log(Number(" ")) // 0
console.log(Number('\t')) // 0

不支持转换的示例:

console.log(Number("a")) // NaN
console.log(Number("123a")) // NaN
console.log(Number('123 123')) // NaN

从上述例子可以看出,如果有一个字符不是数字,结果都会返回 NaN。

ToString

将数据类型转换为字符串。底层调用的是 String(input) 方法。

image

其中最复杂的还是数字和字符串之间的转换。

NumberToString

console.log(String(NaN)) // "NaN"

console.log(String(+0)) // "0"
console.log(String(-0)) // "0"

console.log(String(-1)) // "-1"
console.log(String(+1)) // "1"

console.log(String(Infinity)) // "Infinity"
console.log(String(0x11)) // 17
console.log(String(011)) // 9
console.log(String(1e2)) // 100

ToObject

image

原始数据类型(除 null 与 undefined 外),调用各自对应的包装类型构造函数,转换为对象。

关联阅读: