本文深入解析JavaScript中的原始包装类型(Boolean、Number、String)。通过具体代码示例,阐明原始值如何调用对象方法背后的自动装箱三步流程,并对比引用类型与原始包装对象在生命周期及构造函数调用方式上的核心区别,帮助开发者理解底层执行机制。
前言
观察以下简单代码:变量a被赋值为字符串原始值"str",通过控制台打印该变量时,仅输出“str”。值得注意的是,变量a本身并未定义slice方法,但为何后续能成功调用slice方法并返回结果?
let a = "str";
console.log(a); // "str"
console.log(a.slice(1)) // "tr"要解答上述疑问,必须深入理解JavaScript中的原始包装类型机制。
一、原始包装类型
为了便于对原始值进行操作,ECMAScript规范提供了三种特殊的引用类型:Boolean、Number 和 String。
这三种类型涉及大量方法与属性,本文仅重点介绍其核心的 valueOf() 和 toString() 方法。
1、Boolean类型
当创建Boolean类型的对象实例时,传入的参数会依据转换为Boolean值的规则被判定为true或false。
(1)valueOf():该方法返回一个原始布尔值,即true或false。
let a = new Boolean(true);
console.log(a.valueOf()); // true(2)toString():该方法返回对应的字符串形式,即' true '或' false '。
let b = new Boolean(false);
console.log(b.toString()); // "false"2、Number类型
(1)valueOf():返回对象所持有的原始数值。
let a = new Number(12);
console.log(a.valueOf()); // 12(2)toString():返回对应进制基数下的数值字符串。
let b = new Number(123);
console.log(b.toString()); // "123"3、String类型
valueOf()、toString() 以及 toLocalString() 均继承自Object对象,它们都返回对象的原始字符串值。
let a = new String('str');
console.log(a.valueOf()); // str
console.log(a.toString()); // str
console.log(a.toLocaleString()); // str二、原始包装类型的特点
1、原始值为何能调用方法
let s = "str";
console.log(s.slice(1)) // "tr"如前文代码所示,当第二行访问变量a时,系统以读模式访问内存中保存的值。
在任何以读模式访问字符串值的时刻,后台会自动执行以下三个步骤:
(1)根据该字符串值创建一个String类型的临时实例; (2)调用该实例上特定的方法; (3)销毁该临时实例。
这一过程在逻辑上等同于执行以下三行代码:
// 创建String实例
let s = new String("str");
// 调用特定方法
s.slice(1)
// 销毁实例
s = null这种机制使得原始值具备了类似对象的行为特征。
对于布尔值和数值类型,后台也会执行相同的自动处理步骤。
2、引用类型与原始值包装类型的区别
两者的主要区别在于对象的生命周期管理:
- (1)通过new关键字实例化引用类型后,所得到的实例会在其离开作用域时被销毁;
- (2)自动创建的原始值包装对象仅存在于访问它的那行代码执行期间(因此,运行时无法给原始值动态添加属性和方法)。
3、原始包装类型构造函数与转型函数的区别
以Number类型为例进行说明:
- (1)如果直接调用Number(),执行的是转型函数逻辑,强制进行数值类型转换;
- (2)如果通过new关键字调用Number(),执行的是构造函数逻辑,创建一个Number对象的实例。
let a = Number(1);
console.log(typeof a); // number
let b = new Number(1);
console.log(typeof b); // object这是一个基础但重要的知识点。由于此前学习较为仓促,基础概念掌握不够牢固,特此进行复盘与整理,以巩固理解。