学过Java的时候都知道,Java有自动装箱和自动拆箱,其实js也有。
我们常说“js万物皆对象”,但是基本类型不是对象,它只有一个值,没有属性和方法。自动装箱的作用就是让基本类型可以表现的像对象。
但是对象对象又不能直接参与运算,所以它需要适时的转成基本类型的值,这个过程叫做自动拆箱。
基本类型和包装类
自动装箱对应的是基本类型到包装的转化,自动拆箱反之。js有 7 种基本类型:undefined
、null
、string
、boolean
、number
、bigint
、symbol
。其中只有
string
、boolean
、number
具有包装类,分别是String
、Boolean
、Number
。
手动装箱和拆箱
装箱就是调用对应包装类的构造方法:
var str = new String('hello');
var bool = new Boolean(true);
var num = new Number(123);
拆箱就是调用实例的valueOf
或toString
方法:
new String('hello').valueOf() === 'hello'; // true
new Boolean(true).valueOf() === true; // true
new Number(123).valueOf() === 123; // true
自动装箱和自动拆箱
这里强调的“自动”,也就是装箱和拆箱是隐式发生的。
当尝试调用基本类型的属性和方法的时候就会发生自动装箱。
'hello'.toString(); // string自动装箱
true.toString(); // boolean自动装箱
99.99.toString(); // number自动装箱
基本类型没有属性和方法,这里之所以能调用,是因为发生了自动装箱,相当于:
new String('hello').toString();
new Boolean(true).toString();
new Number(99.99).toString();
有一点需要注意,整数的字面量形式是没法直接自动装箱的:
99.toString(); // Uncaught SyntaxError: Invalid or unexpected token
这是因为整数后面的第一个小数点,会被认为连接小数位,而toString
不是数字,所以报语法错误。
有几种解决办法:
(99).toString(); // 使用括号括起来
99 .toString(); // 整数后面加个空格
99..toString(); // 使用两个点
或者使用变量名:
var num = 99;
num.toString();
再来说说自动拆箱。
当包装类实例和基本类型发生运算时会发生自动拆箱
new Number(1) + 2; // 算数运算
new String('hello') + 'world'; // 字符串拼接
new Boolean(true) == true; // 布尔运算
自动拆箱的本质是类型转换,对象无法跟原始值直接运算,所以要先“解包”成原始值。但是“解包”出来的一定是包装类对应的基本类型吗?比如String
解包的结果一定是string
吗?不一定,这主要取决于和它运算的的另一个值是什么类型。
自动装箱不改变变量类型
例如:
var str = 'hello';
str.toString(); // 发生自动装箱
str instanceof String; // false
typeof str; // string,任然是基本类型
这是因为自动装箱创建的是一个临时变量,调用完就被销毁了,原来的变量还是基本类型。
上面的代码等价于:
new String(str).toString();
临时创建的对象并没有赋值给str
,所以不会改变它的类型。