js中的包装类
前言
在了解包装类之前我们先提一下在JavaScript中有哪些数据类型:
1. 基本数据类型(原始类型)
- Undefined: 表示变量已被声明但没有被赋值。
- Null: 表示一个空对象指针,用于表示一个明确的“无值”。
- Boolean: 表示逻辑值,可以是true或false。
- Number: 用于表示整数和浮点数(包括Infinity和NaN)。
- String: 用于表示文本,是一系列字符的集合。
- Symbol(ES6引入): 用于创建唯一的、不可变的值,主要用作对象的键。
- BigInt(ES10引入): 用于表示任意大小的整数。
2. 引用数据类型(对象类型)
- Object(对象) : 这是最基本的复杂数据类型,可以包含若干键值对(属性),用于存储和操作数据。对象可以是系统提供的对象,如内置的全局对象,或是用户自定义的对象。
- Array(数组) : 数组是一种特殊的对象,其键是数字索引,值可以是任意类型的数据。数组是有序的元素集合,支持一系列操作数组元素的方法。
- Function(函数) : 在JavaScript中,函数也是一种对象,可以被赋值给变量,可以作为其他函数的参数或返回值。函数可以创建独立的可执行代码块,支持参数传递和返回值。
- Date(日期) : 用于处理日期和时间,提供了一系列方法处理和显示日期。
- RegExp(正则表达式) : 用于匹配字符串中的模式,执行强大的文本搜索和替换操作。
- Error对象: 用于处理程序中的错误信息,是异常处理的一部分。
- Map和Set: ES6引入的新数据结构,Map用于存储键值对的集合,其中键可以是任何类型;Set用于存储唯一值的集合。
- WeakMap和WeakSet: 同样是ES6引入的,与Map和Set类似,但它们的引用是弱引用,即垃圾回收机制不考虑它们对对象的引用。
- Promise: 用于处理异步操作的结果,支持链式调用和错误处理。
- Class: ES6引入的面向对象编程的语法糖,实际上也是基于函数和原型链实现的。
两种数据类型的区别
-
存储方式:
- 基本数据类型:直接存储在栈内存中,每个变量都包含实际的值。这意味着,当一个基本类型的变量被赋予另一个变量时,会创建该值的一个副本,两个变量分别独立存储各自的值。
- 引用数据类型:存储在堆内存中,而变量中存储的是指向堆中对象的引用(内存地址)。当一个引用类型的变量被赋予另一个变量时,实际上是复制了引用,两个变量最终指向的是同一块堆内存中的对象,因此修改其中一个变量会影响到另一个。
-
值的可变性:
- 基本数据类型:值是不可变的,一旦创建就无法更改其内容。你不能给基本数据类型的值添加属性或方法。
- 引用数据类型:值是可以变的,可以通过引用修改对象的属性或方法。因为多个变量可能指向同一对象,所以对一个对象的修改会影响到所有指向它的变量。
-
比较方式:
- 基本数据类型:使用
==
或===
比较时,比较的是值是否相等。===
严格相等运算符还会检查类型。 - 引用数据类型:使用
==
或===
比较时,比较的是它们的引用(内存地址)是否相同,而不是值是否相等。即使两个对象的内容完全一样,它们的引用也可能不同,因此被认为是不相等的。
- 基本数据类型:使用
-
应用场景:
- 基本数据类型:适合存储简单的、不可变的数据,如数字、字符串、布尔值等。
- 引用数据类型:适合存储复杂的数据结构,如对象、数组、函数等,这些类型可以包含多个值和复杂的结构。
-
内存管理:
- 基本数据类型:由于值直接存储在栈中,当不再使用时,内存回收相对简单直接。
- 引用数据类型:存储在堆中,且由垃圾回收机制管理,需要跟踪引用的数量来确定何时可以回收对象所占的内存
正文
包装类,啥是包装类呢?包装类是一种特殊的对象类型,用于将原始数据类型转换为对象。这种转换是临时的,即在访问原始值时,JavaScript会自动创建一个相应的包装对象,以便可以调用对象方法。举例看:
let num = 25;
console.log(num.toFixed(2)); // 输出 "25.00"
在这段代码中,num
是一个基本数据类型——Number。然而,当我们尝试调用.toFixed(2)
方法时,JavaScript自动创建了一个临时的Number
对象,该对象允许我们调用.toFixed()
这样的方法。调用结束后,这个临时对象会被销毁,num
依旧保持为原始的数值类型。
包装类的种类
JavaScript为每种基本数据类型提供了相应的包装对象,分别是:
- String: 用于字符串的包装对象。它允许字符串值像对象那样使用方法,比如
.length
,.toUpperCase()
,.toLowerCase()
等。 - Number: 为数值提供包装对象,支持诸如
.toFixed()
,.toPrecision()
,.toString()
等方法。 - Boolean: 提供了布尔值的包装对象,尽管它的使用不如String和Number频繁,但理论上也可以通过Boolean对象调用方法。
动态转换与静态方法
值得注意的是,原始类型到包装对象的转换是JavaScript引擎自动完成的,这一过程称为“装箱”(boxing)。此外,每个包装类还提供了一些静态方法,可以在不创建实例的情况下直接操作原始类型值,例如:
let str = "Hello World!";
console.log(String.fromCharCode(72, 101, 108, 108, 111)); // 输出 "Hello"
特别注意
尽管包装类为操作原始数据类型提供了便利,但直接使用new
关键字创建这些包装类的实例(如new String('text')
)在大多数情况下是不推荐的。这样做不仅会产生不必要的性能开销,还可能导致意料之外的行为,特别是当比较这些实例与原始类型值时。
总结
包装类在JavaScript中扮演着重要的角色,它们使基本数据类型能够像对象一样使用方法,增强了语言的灵活性和易用性。理解包装类的工作原理对于深入掌握JavaScript的数据类型和内存管理至关重要。然而,在日常编码实践中,应当谨慎使用直接实例化包装类的方式,以避免潜在的问题和效率损失。
结尾来道面试题吧
var str='abc'
str+=1
var text=typeof (str)
if (text.length===6){
text.sign='typeOf的返回结果可能是String'
}
console.log(text.sign);
第一眼看上去感觉就是输出'typeOf的返回结果可能是String'
,然而当我们去验证就发现他输出的是undefined。我们可以根据上面的知识来解释:因为在执行console.log(text.sign);
之前,text
的值是"string"
,其长度为6,满足条件text.length === 6
,但是字符串"string"
本身是没有sign
属性的。因此,尝试访问text.sign
时,结果为undefined
。
转载自:https://juejin.cn/post/7377697380215210021