文章目录

在 JavaScript 中,有时会碰到以下两种类型的代码:

1.
var num = 123;
var str = ‘123’;
num.toFixed(2); // ‘123.00’
str.split(‘’); // [‘1’,’2’,’3’]
2.
var num = [1,2,3];
var str = {
name:’hahaha’
};
console.log(num+1); //1,2,31
String(str); //‘[object Object]’

在第一段代码中,我们在两个基本类型的值上调用方法。众所周知,在 JavaScript 中只有 Object 类型才有方法。在第二段代码中,我们可以把两个 Object 类型的值当做基本类型的值直接使用。这就是 JavaScript 装箱与拆箱在代码中的具体体现。

下面我分别来解释一下 JavaScript 中的装箱与拆箱。

一:装箱

所谓装箱,就是把基本类型转变为对应的对象。装箱分为隐式和显示。

隐式装箱
每当读取一个基本类型的值时,后台会创建一个该基本类型所对应的对象。在这个基本类型上调用方法,其实是在这个基本类型对象上调用方法。这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立刻被销毁。具体到代码如下:

    num.toFixed(2); // '123.00'
//上方代码在后台的真正步骤为
    var c = new Number(123);
    c.toFixed(2);
    c = null;

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

  1. 创建一个 Number 类型的实例。
  2. 在实例上调用方法。
  3. 销毁实例。

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

var obj = new String('123');

二:拆箱

拆箱与装箱相反,把对象转变为基本类型的值。拆箱过程内部调用了抽象操作 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

Gwen Weustink  2016-03-02 09-53-30 .jpg
Gwen Weustink  2016-03-02 09-53-30 .jpg

文章目录