javaScript 的基本类型为什么有基本包装类型的存在?

前言

今天复习JS基础知识,在看到基本数据类型和引用数据类型的时候,突然有些疑问为什么基本数据类型还会有包装类型,基本类型的包装类型的具体作用是什么?带着这个疑问,我打开了百度...

基本原理

基本数据类型包括 string,number,boolean,undefined,null 和 es6 的 symbol 这六种,对于基本数据类型,我们知道它们不存在属性和方法,但是通过字面量形式定义的基本数据变量可以直接调用一些方法:

let str = 'abcdef';
str.substring(0, 3); // 'abc'

let num = 12;
num.toFixed(2); // 12.00

let bool = new Boolean(true);
bool.toString(); // 'true'

正是由于有基本包装类型的存在才会使得上面的基本数据类型的变量可以调用方法相关内置的方法。
为了便于操作基本类型值,ECMAScript 提供了一些特殊的引用类型:比如 Boolean、Number 和String等。这些类型与其他引用类型相似,但具有与各自的基本类型相应的特殊行为。除了 undefined 和 null 外,其余基本数据类型都有相应的包装类型对象:String, Boolean, Number, Symbol。
实际上,每当读取一个基本类型值得时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。如下例子:

let s1 = 'abcdef';
let s2 = str.substring(0, 3); // 'abc'

这个例子中的 s1 变量被赋值了一个字符串,字符串是基本数据类型;下一行代码调用s1.subString() 方法,并将返回结果保存在了 s2 中。我们知道,基本类型不是对象,因而它们不应该有方法(尽管实际上它们确实有方法)。其实,为了让我们实现这种直观的操作,后台已经自动完成了一系列的处理。当第二行代码访问s1时,访问过程处于一种读取模式,也就是从内存中读取这个字符串的值。而在读取模式中访问字符串时,后台都会自动完成下列处理。

  1. 创建一个String类型的实例;
  2. 在实例上调用指定的方法;
  3. 调用完毕之后立即销毁这个实例;

可以将以上三个步骤想象成是执行了下列ECMAScript代码:

let s1 = 'abcdef';
let s2 = s1.substring(0, 3);
// 以下代码是在后台执行完成的
// 当s1调用方法时,会生成一个临时变量,默认创建一个s1的包装对象实例
let temp = new String(s1);
let s2 = tem.substring(0,3); // 'abc'
// 销毁临时变量
tem = null;

重点在于调用方法时才创建了对应类型包装对象实例,在方法调用完毕之后又立即销毁了临时包装类型变量。

引用类型和基本包装类型的主要区别就是对象的生命周期,使用 new 创建的引用类型(基本包装类型)实例,当执行流离开当前作用域之前都一直保存在内存中,而自动创建的基本包装类型的对象实例,则只存在于一行代码执行的瞬间,然后就被销毁。这意味着我们不能给使用基本类型变量添加属性和方法。

let s1="abced"
s1.color="red";
console.log(s1.color); //undefined

在此,第二行代码试图为字符串 s1 添加一个 color 属性。但是当第三行代码访问 s1 时,其 color 属性为 undefined 。原因在于,第二行创建的 String 对象在执行第三行代码时已经被销毁了。第三行代码又创建自己的 String 对象,而该对象没有 color 属性。
我们可以显示的调用 Boolean,Number 和 String 来创建基本包装类型的实例。不过,应该在绝对必要的情况下这样做,因为这种做法很容易让人分不清自己是在处理基本包装类型还是引用类型的值。对基本包装类型的实例调用 typeof 会返回 'object',而且所有的基本包装类型都会被转换为布尔值 true。
Object构造函数也会像工厂方法一样,根据传入值得类型返回相应基本包装类型的实例。例如:

let obj = new Object('abc');
console.log(obj instanceof String); // true

把字符串传给Object构造函数,就会创建String的实例;而传入数值参数会得到Number的实例,传入布尔值参数就会得到Boolean的实例。
要注意的是,使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。

let value = "25";
let number = Number(value); //转型函数
console.log(typeof number); //"number"

let obj = new Number(value); //构造函数
console.log(typeof obj); //"object" 

在这个例子中,变量number中保存的是基本类型的值25,而变量obj中保存的是Number的实例。
尽管我们不建议显式的创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的。而每个基本包装类型都提供了操作相应值的便捷方法。

总结

  • 基本包装类型的实例会在我们调用一些基本类型变量方法或属性的时候被自动创建
  • 我们对基本类型变量调用的方法或访问属性,Js底层会对基本包装类型实例操作
  • 基本包装类型的实例只存在于一行代码执行的一瞬间,然后会被立即销毁,因此无法设置属性或方法
  • 不推荐手动创建基本包装类型实例

之前学习的时候并没有十分理解这部分的内容,今天算是重新学习了一下这部分知识。

参考文章:
Js基本包装类型(含原理)_scluis的博客-CSDN博客_js包装类型
浅谈javascript中基本包装类型

posted @ 2022-07-07 22:24  公瑾当年  阅读(121)  评论(0编辑  收藏  举报