# 类型转换

[toc]

将值从一种类型转换为另一种类型通常称为类型转换。

ES6 前,JavaScript 共有六种数据类型:Undefined、Null、Boolean、Number、String、Object。后面又新增Symbol 和BigInt。

# 1、原始值 => 布尔

我们使用Boolean函数将类型转换为布尔类型,在js中,只有6种值可以被转换成false, 其他都被转换成true。

console.log(Boolean()); // false
console.log(Boolean(false)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
console.log(Boolean(+0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('')); // false

需要注意的是,不传递任何参数时,返回的是false。

# 2、原始值 => 数字

我们可以使用 Number 函数将类型转换成数字类型,如果参数无法被转换为数字,则返回 NaN。

如果 Number 函数不传参数,返回 +0,如果有参数,调用 ToNumber(value)

注意这个 ToNumber 表示的是一个底层规范实现上的方法,并没有直接暴露出来。

参数类型 返回值
Undefined NaN
Null +0
Boolean The result is 1 if the argument is true. The result is +0 if the argument is false.
Number 返回与之相等的值
String 比较复杂看下面的例子。
Object Apply the following steps:Let primValue be ToPrimitive (opens new window)(input argument, hint Number).Return ToNumber(primValue).调用 对象的toPrimitive,获取原始值, 再用原始值调用toNumber
console.log(Number()) // +0

console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0

console.log(Number(false)) // +0
console.log(Number(true)) // 1

console.log(Number("123")) // 123
console.log(Number("-123")) // -123
console.log(Number("1.2")) // 1.2
console.log(Number("000123")) // 123
console.log(Number("-000123")) // -123

console.log(Number("0x11")) // 17

console.log(Number("")) // 0
console.log(Number(" ")) // 0

console.log(Number("123 123")) // NaN
console.log(Number("foo")) // NaN
console.log(Number("100a")) // NaN

如果通过 Number 转换函数传入一个字符串,它会试图将其转换成一个整数或浮点数,而且会忽略所有前导的 0,如果有一个字符不是数字,结果都会返回 NaN。

# 3、原始值 => 字符串

我们使用 String 函数将类型转换成字符串类型。如果 String 函数不传参数,返回空字符串,如果有参数,调用 ToString(value),而 ToString 也给了一个对应的结果表。表如下:

参数类型 结果
Undefined "undefined"
Null "null"
Boolean 如果参数是 true,返回 "true"。参数为 false,返回 "false"
Number 又是比较复杂,可以看例子
String 返回与之相等的值
console.log(String(undefined)); // 'undefined'
console.log(String(null)); // 'null'
console.log(String(false)); // 'false'
console.log(String(true)); // 'true'
console.log(String(0)); // '0'
console.log(String(-0)); // '0'
console.log(String(NaN)); // 'NaN'
console.log(String(Infinity)); // 'Infinity'
console.log(String(-Infinity)); // '-Infinity'
const str1 = String(1);
console.log(str1, typeof str1); // '1' string
console.log(str1 === '1'); // true
console.log(str1 === 1); // false

# 4、原始值 => 对象

原始值到对象的转换非常简单,原始值通过调用 String()、Number() 或者 Boolean() 构造函数,转换为它们各自的包装对象。

null 和 undefined 属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误 (TypeError) 异常,而不会执行正常的转换。

var a = 1;
console.log(typeof a); // number
var b = new Number(a);
console.log(typeof b); // object

String()、Number() 、 Boolean() 可以称为包装类。

# 5、对象 => 布尔值

对象到布尔值的转换非常简单:所有对象(包括数组和函数)都转换为 true。

# 6、对象 => 字符串和数字

# 6.1 toString()

对象转字符串和数字都是通过被转换对象的一个方法来完成的。而 JavaScript 对象有两个不同的方法来执行转换,一个是 toString,一个是 valueOf。所有的对象除了 null 和 undefined 之外的任何值都具有 toString 方法,通常情况下,它和使用 String 方法返回的结果一致。toString 方法的作用在于返回一个反映这个对象的字符串,然而这才是情况复杂的开始。

# 6.3 valueOf()

基础类型(Number,String.Boolean等)的valueOf返回其本身

而另一个转换对象的函数是 valueOf,表示对象的原始值。默认的 valueOf 方法返回这个对象本身,数组、函数、正则简单的继承了这个默认方法,也会返回对象本身。日期是一个例外,它会返回它的一个内容表示: 1970 年 1 月 1 日以来的毫秒数。

const arr = [1];
console.log(arr.valueOf() === arr); // true
console.log(new Date(2023, 7 - 1, 31).valueOf()); // 1690732800000

# 6.3 Object toString的步骤

参数类型 结果
Object 1. primValue = ToPrimitive(input, String)
2. 返回ToString(primValue).

所谓的 ToPrimitive 方法,其实就是输入一个值,然后返回一个一定是基本类型的值。这个ToPrimitive 不是一个暴露的API。

# 6.3 Object toNumber的步骤

参数类型 结果
Object 1. primValue = ToPrimitive(input, String)
2. 返回toNumber(primValue).

# 6.4 ToPrimitive

ToPrimitive(input[, PreferredType])

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

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

当不传入 PreferredType 时,如果 input 是日期类型,相当于传入 String,否则,都相当于传入 Number。

如果传入的 input 是 Undefined、Null、Boolean、Number、String 类型,直接返回该值。

如果是 ToPrimitive(obj, Number),处理步骤如下:

  1. 如果 obj 为 基本类型,直接返回
  2. 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
  3. 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
  4. 否则,JavaScript 抛出一个类型错误异常。

如果是 ToPrimitive(obj, String),处理步骤如下:

  1. 如果 obj为 基本类型,直接返回
  2. 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
  3. 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
  4. 否则,JavaScript 抛出一个类型错误异常。

TIP

toPrimitive的默认行为可以通过复写 Symbol.toPrimitive 属性覆盖。

# 6.5 对象转字符串 总结

所以总结下,对象转字符串(就是 String() 函数)可以概括为:

  1. 如果对象具有 toString 方法,则调用这个方法。如果他返回一个原始值,JavaScript 将这个值转换为字符串,并返回这个字符串结果。
  2. 如果对象没有 toString 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf 方法。如果存在这个方法,则 JavaScript 调用它。如果返回值是原始值,JavaScript 将这个值转换为字符串,并返回这个字符串的结果。
  3. 否则,JavaScript 无法从 toString 或者 valueOf 获得一个原始值,这时它将抛出一个类型错误异常。

# 6.6 对象转数字 总结

对象转数字的过程中,JavaScript 做了同样的事情,只是它会首先尝试 valueOf 方法

  1. 如果对象具有 valueOf 方法,且返回一个原始值,则 JavaScript 将这个原始值转换为数字并返回这个数字
  2. 否则,如果对象具有 toString 方法,且返回一个原始值,则 JavaScript 将其转换并返回。
  3. 否则,JavaScript 抛出一个类型错误异常。
console.log(Number({})) // NaN
console.log(Number({a : 1})) // NaN

console.log(Number([])) // 0
console.log(Number([0])) // 0
console.log(Number([1, 2, 3])) // NaN
console.log(Number(function(){var a = 1;})) // NaN
console.log(Number(/\d+/g)) // NaN
console.log(Number(new Date(2010, 0, 1))) // 1262275200000
console.log(Number(new Error('a'))) // NaN

注意,在这个例子中,[][0] 都返回了 0,而 [1, 2, 3] 却返回了一个 NaN。我们分析一下原因:

当我们 Number([]) 的时候,先调用 []valueOf 方法,此时返回 [],因为返回了一个对象而不是原始值,所以又调用了 toString 方法,此时返回一个空字符串,接下来调用 ToNumber 这个规范上的方法,参照对应表,转换为 0, 所以最后的结果为 0

而当我们 Number([1, 2, 3]) 的时候,先调用 [1, 2, 3]valueOf 方法,此时返回 [1, 2, 3],再调用 toString 方法,此时返回 1,2,3,接下来调用 ToNumber,参照对应表,因为无法转换为数字,所以最后的结果为 NaN

# 7、类型转换的面试题

# 7.1 定义一个变量a,使if (a == 1 && a == 2 && a == 3)条件成立

const a = {
  value: 0,
  valueOf() {
    ++this.value;
    return this.value;
  },
  /* toString() {
    ++this.value;
    return this.value;
  } */
};
// 要点就是这里必须是looseEqual, 才会进行类型隐式转换
if (a == 1 && a == 2 && a == 3) {
  console.log(a);
}

类型转换(上) (opens new window)

上次更新: 1/22/2025, 9:39:13 AM