必看!JavaScript 包装类全方位解析

前言

在JavaScript中,包装类是一种特殊的对象类型,用于将原始数据类型(如字符串、数字和布尔值)转换为对象。这种转换是临时的,即在访问原始值时,JavaScript会自动创建一个相应的包装对象,以便可以调用对象方法。在本文中,我们将深入探讨JavaScript中包装类的概念、用途以及相关的注意事项。

数据类型

1. 原始类型

  • 数值(Number) :用于表示数字,可以进行数学运算。
  • 字符串(String) :用于表示文本,可以进行文本操作和连接。
  • 布尔值(Boolean) :用于表示真或假,常用于条件判断。
  • 未定义(Undefined) :表示未初始化的变量,或者不存在的属性。
  • 空值(Null) :表示空值或者未知值。
javascript 复制代码
let num = 123          //数字
let str = 'hello'     // 字符串
let flag = true      //通常用于判断语句
let un = undefined  //未定义
let nu = null      //空值

这些变量展示了JavaScript中的不同原始数据类型,包括数字、字符串、布尔值、未定义和空值。

2. 引用类型:

  • 对象(Object) :用于存储多个键值对,常用于构建复杂的数据结构和管理对象属性和方法。
  • 数组(Array) :用于存储一系列的值,常用于列表和集合的操作。
  • 函数(Function) :用于封装可重用的代码块,常用于实现特定功能和逻辑。
javascript 复制代码
let obj = {}              // 对象字面量
let fu = function() {}   // 函数
let arr = []            // 数组
let date = new Date()  // 日期对象

这些都是JavaScript中常见的引用类型示例。对象字面量用于创建普通对象,函数是JavaScript中的一等公民,可以作为变量赋值、作为参数传递等,数组用于存储一组数据,而日期对象用于处理日期和时间相关的操作。

3. 两者区别

在这个例子中,a 和 b 都是原始类型的变量。

ini 复制代码
let a = 1
let b = a
a = 2
console.log(b); // 输出为 1

首先,将 a 的值赋给了 b,此时 b 的值为 1。然后,将 a 的值修改为 2。但是由于 b 是从 a 复制的原始类型的值,所以它们之间并没有共享关系,因此 b 的值保持不变,仍然为 1。因此,console.log(b) 的输出结果为 1。


在这个例子中,a 和 b 都是指向同一个对象的引用类型的变量。

ini 复制代码
let a = {                          
    age: 18
}
let b = a
a.age = 20
console.log(b.age); // 输出为 20

首先,将 a 的引用赋给了 b,因此它们指向同一个对象。然后修改了 a 对象的 age 属性为 20,由于 b 是指向 a 的引用,因此 b.age 的值也会被更新为 20。所以最终 console.log(b.age) 的输出结果是 20。这展示了对象的属性是可以通过引用进行修改的。

下面我们再来看一个例子:

javascript 复制代码
let obj = {
    name: '小明',
    age: 18
}
console.log(obj.name)  // 输出 '小明'

那如果把obj.name换成obj['name']结果会有变化吗?

javascript 复制代码
let obj = {
    name: '小明',
    age: 18
}
console.log(obj.['name'])  // 结果依然输出'小明'

请注意 :这里不能把obj['name']换成obj[name]!这是这是因为 name 没有被定义为一个变量或者常量,所以它会被当作一个变量名来进行解析。

对象

对象的创建

ini 复制代码
var obj = {}  
var obj2 = new Object(); 
console.log(obj,obj2);

上面的代码展示了两种创建对象的方式:对象字面量和构造函数。

  1. 对象字面量方式:
ini 复制代码
var obj = {}; // 使用花括号创建一个空对象

通过使用花括号 {},你可以直接创建一个空对象 obj。你可以在对象字面量中添加属性和方法。

  1. 构造函数方式:
javascript 复制代码
var obj2 = new Object(); // 使用Object构造函数创建一个空对象

通过使用 new Object(),你可以调用内置的构造函数 Object 来创建一个空对象 obj2。这种方式也可以用于创建具有自定义属性和方法的对象。

当你打印这两个对象时,会输出它们的字符串表示形式。例如:

arduino 复制代码
console.log(obj, obj2); // 输出为 {} {}

这将分别打印出对象 obj 和 obj2 的字符串表示形式,即 {}。这表示这两个对象都是空对象,因为没有给它们添加任何属性或方法。

自定义构造函数

自定义构造函数是指你可以使用 JavaScript 中的函数来创建自定义对象类型。通过使用构造函数,你可以定义对象的初始状态和行为,并且可以创建该类型的多个实例。

下面是一个简单的示例,展示了如何创建一个自定义的构造函数以及如何使用它来创建对象实例:

ini 复制代码
function Car() {
    this.name = 'BMW'
    this.height = 1400
    this.width = 4900
    this.weight = 1000
}
let car = new Car()
console.log(car);

让我们一行一行地来解释:

csharp 复制代码
function Car() {

这一行代码定义了一个名为 Car 的构造函数,它用于创建代表汽车的对象。

ini 复制代码
    this.name = 'BMW';
    this.height = 1400;
    this.width = 4900;
    this.weight = 1000;

在构造函数内部,通过使用 this 关键字,我们为即将创建的汽车对象设置了几个属性:name、height、width 和 weight。这些属性表示了汽车的名称、高度、宽度和重量。构造函数定义结束。

ini 复制代码
let car = new Car();

当执行 let car = new Car(); 这一行代码时,会发生以下步骤:

  1. 关键字 new 创建了一个新的对象。
  2. 构造函数 Car() 被调用,作为对象的初始化函数。
  3. 在构造函数内部,关键字 this 引用了新创建的对象。
  4. 构造函数中的代码将属性值分配给对象。在这个例子中,name 属性被赋值为 'BMW',height 属性被赋值为 1400,width 属性被赋值为 4900,weight 属性被赋值为 1000。
  5. 构造函数执行完毕后,返回新创建的对象。
  6. 新创建的对象被赋值给变量 car。

最终,car 变量指向了一个具有属性 name、height、width 和 weight 的汽车对象。

用代码形式表示:

ini 复制代码
function Car() {
    this.name = 'BMW'
    this.height = 1400
    this.width = 4900
    this.weight = 1000
           // var this = { 关键字 `new` 创建了一个新的对象。
           // name: 'BWM',
           // this.height = 1400
           // this.width = 4900
           // this.weight = 1000
           // }    
           // return this
}
let car = new Car()
console.log(car);

以上面代码进行拓展:

ini 复制代码
function Car(color) {
    this.name = 'BMW'; // 设置汽车的名称为'BMW'
    this.height = 1400; // 设置汽车的高度为1400
    this.width = 4900; // 设置汽车的宽度为4900
    this.weight = 1000; // 设置汽车的重量为1000
    this.color = color; // 设置汽车的颜色为传入的参数color
}

let car = new Car('green'); // 创建一个颜色为'green'的汽车对象
let car2 = new Car('pink'); // 创建一个颜色为'pink'的汽车对象

car.name = '劳斯莱斯'; // 修改car对象的名称为'劳斯莱斯'

console.log(car); // 打印输出car对象的内容
console.log(car2); // 打印输出car2对象的内容

car输出结果为:

car2输出结果为:

尽管我们对 car 对象的 name 属性进行了修改,但这并不会改变 car 对象本身的结构。换句话说,car 对象仍然是通过 Car 构造函数创建的,拥有相同的属性和方法。

在代码中,我们使用 new Car('green') 创建了 car 对象,并将其颜色属性设置为 'green'。然后,我们通过 car.name = '劳斯莱斯' 将 car 对象的 name 属性修改为 '劳斯莱斯'。

尽管 car 对象的 name 属性被修改了,但它仍然是一个 Car 对象,具有 Car 构造函数定义的其他属性(如 height、width、weight 和 color)和方法(如果有的话)。

因此,在打印 car 和 car2 对象时,它们的结构是相同的,都是由 Car 构造函数定义的。只是它们的某些属性值不同,例如 color 属性的值不同。

包装类

在前面我们已经铺垫了一些基础知识,下面让我们走进包装类。

什么是包装类

在JavaScript中,包装类是一种特殊的对象类型,它们用于将基本数据类型(如字符串、数字、布尔值)包装成对象。这些包装类提供了一些便捷的方法,使得我们可以像操作对象一样操作基本数据类型。

在JavaScript中,有三种主要的包装类:

  • String:用于包装字符串类型
  • Number:用于包装数字类型
  • Boolean:用于包装布尔类型
ini 复制代码
var obj = {}
obj.a = 1

当你执行 var obj = {} 时,你创建了一个空的对象 obj。这个对象实际上是一个普通的 JavaScript 对象,它并不是通过包装类创建的。

然后,当你执行 obj.a = 1 时,JavaScript 引擎会根据需要将基本数据类型转换为对应的包装类。在这种情况下,属性 a 被赋予了一个数字值 1,而数字是一种基本数据类型。因此,在给属性 a 赋值时,JavaScript 引擎会将数字 1 隐式地转换为一个 Number 包装对象。

实际上,JavaScript 引擎会在后台执行类似于以下的操作:

ini 复制代码
obj.a = new Number(1);

这样,属性 a 实际上被赋予了一个包装了数字 1 的 Number 对象。因此,我们可以像操作对象一样操作属性 a。

隐式包装类操作

隐式包装类操作是指在JavaScript中,当我们对基本数据类型(如字符串、数字和布尔值)进行属性访问或方法调用时,JavaScript引擎会隐式地将基本数据类型转换为对应的包装类对象。这样,我们就可以像操作对象一样操作基本数据类型。

ini 复制代码
var num = 123
num.a = 'hello'
console.log(num.a);

在这段代码中,首先我们创建了一个名为num的变量,并将其赋值为数字类型的基本数据123。

接着,我们尝试给num这个基本数据类型添加一个属性a,并将其赋值为字符串'hello'。

然而,由于JavaScript中的基本数据类型是不可变的,所以在尝试给num添加属性时,JavaScript引擎会对num进行隐式包装类操作,将其转换为对应的Number包装类对象。然后,它会在临时创建的Number包装类对象上添加属性a,并赋值为'hello'。

但是,在接下来的代码中,由于num本身并不是一个对象,也没有a属性,所以会返回undefined。这是因为在这个过程中,我们只是在临时创建的Number包装类对象上添加了属性,而并没有改变原始的基本数据类型num的值。

因此,最终的输出结果会是undefined。

让我们再看一段代码:

ini 复制代码
var str = 'abcd'
str.length = 2
console.log(str);

在这段代码中,我们首先创建了一个名为 str 的变量,并将其赋值为字符串 'abcd'。

接着,我们尝试给 str 这个字符串类型的基本数据添加一个属性 length,并将其赋值为数字 2。

然而,与之前提到的类似情况一样,JavaScript 中的字符串是不可变的,它们是原始值,不是对象。当我们尝试给字符串添加属性时,JavaScript 引擎会对这个字符串进行临时的包装(boxing),将其转换为对应的包装类对象(String 对象),然后在这个临时创建的对象上添加属性。

但是,一旦这个表达式结束,这个临时创建的包装类对象就会被丢弃,而我们所添加的属性也会随之消失。因此,尽管我们可以给字符串添加属性,但这些属性并不会被保存下来,因为它们只存在于临时的包装类对象上,而不是原始的字符串上。

所以,最终的输出结果仍然是原始的字符串 'abcd',而不是具有新属性的字符串。

如果将上面最后一行输出代码(str)换成(str.length),输出结果将会和本小结第一段代码输出值一样为undefined。

上面两段代码是原始类型,下面我们看引用类型代码

ini 复制代码
var arr = [1,2,3,4]
arr.length = 2
console.log(arr);

在这段代码中,我们首先创建了一个名为 arr 的变量,并将其赋值为一个包含数字 1、2、3 和 4 的数组。

接着,我们将数组 arr 的 length 属性修改为 2。

与之前的原始类型示例不同,数组是对象类型,它可以拥有属性和方法。当我们修改数组的 length 属性时,实际上是在改变数组的长度。如果将 length 属性设置为小于原始数组长度的值,数组会被截断,多余的部分会被删除;如果将 length 属性设置为大于原始数组长度的值,数组会被扩展,新增的部分会用 undefined 填充。

因此,最终的输出结果是 [1, 2],这是一个仅包含了原始数组前两个元素的新数组。与原始类型不同,数组的 length 属性的修改确实对数组进行了改变。



以上就是今天的全部内容了,欢迎补充~

相关推荐
溪语流沙35 分钟前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
逐光者93341 分钟前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
To_OC1 小时前
同样是让 AI 写全栈,为什么别人一句话就够了
前端·前端框架·next.js
CDwenhuohuo1 小时前
electron pc项目打包成桌面端
前端·javascript·electron
前端大斗师1 小时前
「大于 1000」把 1000 元那单也算进去了:我在 Vue3 订单页对了 10 句话
前端·人工智能·typescript·大模型·原力计划
Jmyd01232 小时前
用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路
前端·3d·vr·三维数字化
刘天远3 小时前
Agent成本核算实现:事件表、状态分布与Python归集
前端·数据库·人工智能·python
欣欣之王来了3 小时前
开发环境准备:Node.js、npm、VS Code安装配置
前端·学习·架构·项目·vue3教程
xiaolinudao1233 小时前
将多个 Excel 表格中的数据合并到单个表中|6 种实现方案全解析
java·前端·excel
LRL_3 小时前
跨平台 Node 模块安装指南:如何利用 pnpm/npm 配置`supportedArchitectures` 锁定平台依赖
前端·npm·node.js