基本类型对应的内置对象,以及他们之间的装箱拆箱操作

1,600 阅读2分钟

一: 装箱

我们会看到以下代码:

const str = 'hello world';
str.substring(0,3);

const num = 12.345;
num.toFixed(1);

众所周知,javascript只有Object类型才有方法。上面代码能执行正是因为自动装箱的结果。

什么是装箱呢?就是将基本类型转成对象类型的操作。分为显示装箱和隐式装箱。

显示装箱:

通过内置对象String、Boolean、Number等可以对基本类型进行显示装箱

const strObj = new String('hello world');

隐式装箱:

当读取一个基本类型值时,后台会为该基本类型创建一个对应的基本类型包装对象。在这个基本类型上调用方法,实际上是在这个基本类型包装对象上调用方法。这个基本类型包装对象是临时的,它只存在于方法调用那一行代码的的瞬间,一旦调用完毕就立即销毁。

num.toFixed(1);

// 在后台的具体执行如下:

const c = new Number(12.345);

c.toFixed(1);

c = null;

当我们访问 num 时,要从内存中读取这个数字的值,此时访问过程处于读取模式。在读取模式中,后台进行了三步处理:

  • 创建一个 Number 类型的实例。

  • 在实例上调用方法。

  • 销毁实例。

二、拆箱

拆箱与装箱相反,将对象转变成基本类型的值。拆箱过程内部调用了抽象操作 ToPrimitive 。该操作接受两个参数,第一个参数是要转变的对象,第二个参数 PreferredType 是对象被期待转成的类型。第二个参数不是必须的,默认该参数为 number,即对象被期待转为数字类型。有些操作如 String(obj) 会传入 PreferredType 参数。有些操作如 obj + " " 不会传入 PreferredType。

具体转换过程是这样的。默认情况下,ToPrimitive 先检查对象是否有 valueOf 方法,如果有则再检查 valueOf 方法是否有基本类型的返回值。如果没有 valueOf 方法或 valueOf 方法没有返回值,则调用 toString 方法。如果 toString 方法也没有返回值,产生 TypeError 错误。

PreferredType 影响 valueOf 与 toString 的调用顺序。如果 PreferrenType 的值为 string。则先调用 toString ,再调用 valueOf。

具体测试代码如下:

var obj = {
    valueOf : () => {console.log("valueOf"); return []},
    toString : () => {console.log("toString"); return []}
}

String(obj)
// toString
// valueOf
// Uncaught TypeError: Cannot convert object to primitive value

obj+' '
//valueOf
//toString
// Uncaught TypeError: Cannot convert object to primitive value

Number(obj)
//valueOf
//toString
// Uncaught TypeError: Cannot convert object to primitive value