前言
在JavaScript中,包装类是一种特殊的对象类型,用于将原始数据类型(如字符串、数字和布尔值)转换为对象。这种转换是临时的,即在访问原始值时,JavaScript会自动创建一个相应的包装对象,以便可以调用对象方法。在本文中,我们将深入探讨JavaScript中包装类的概念、用途以及相关的注意事项。
数据类型
1. 原始类型
- 数值(Number) :用于表示数字,可以进行数学运算。
- 字符串(String) :用于表示文本,可以进行文本操作和连接。
- 布尔值(Boolean) :用于表示真或假,常用于条件判断。
- 未定义(Undefined) :表示未初始化的变量,或者不存在的属性。
- 空值(Null) :表示空值或者未知值。
let num = 123 //数字
let str = 'hello' // 字符串
let flag = true //通常用于判断语句
let un = undefined //未定义
let nu = null //空值
这些变量展示了JavaScript中的不同原始数据类型,包括数字、字符串、布尔值、未定义和空值。
2. 引用类型:
- 对象(Object) :用于存储多个键值对,常用于构建复杂的数据结构和管理对象属性和方法。
- 数组(Array) :用于存储一系列的值,常用于列表和集合的操作。
- 函数(Function) :用于封装可重用的代码块,常用于实现特定功能和逻辑。
let obj = {} // 对象字面量
let fu = function() {} // 函数
let arr = [] // 数组
let date = new Date() // 日期对象
这些都是JavaScript中常见的引用类型示例。对象字面量用于创建普通对象,函数是JavaScript中的一等公民,可以作为变量赋值、作为参数传递等,数组用于存储一组数据,而日期对象用于处理日期和时间相关的操作。
3. 两者区别
在这个例子中,a
和 b
都是原始类型的变量。
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
都是指向同一个对象的引用类型的变量。
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
。这展示了对象的属性是可以通过引用进行修改的。
下面我们再来看一个例子:
let obj = {
name: '小明',
age: 18
}
console.log(obj.name) // 输出 '小明'
那如果把obj.name
换成obj['name']
结果会有变化吗?
let obj = {
name: '小明',
age: 18
}
console.log(obj.['name']) // 结果依然输出'小明'
请注意:这里不能把obj['name']
换成obj[name]
!这是这是因为 name
没有被定义为一个变量或者常量,所以它会被当作一个变量名来进行解析。
对象
对象的创建
var obj = {}
var obj2 = new Object();
console.log(obj,obj2);
上面的代码展示了两种创建对象的方式:对象字面量和构造函数。
- 对象字面量方式:
var obj = {}; // 使用花括号创建一个空对象
通过使用花括号 {}
,你可以直接创建一个空对象 obj
。你可以在对象字面量中添加属性和方法。
- 构造函数方式:
var obj2 = new Object(); // 使用Object构造函数创建一个空对象
通过使用 new Object()
,你可以调用内置的构造函数 Object
来创建一个空对象 obj2
。这种方式也可以用于创建具有自定义属性和方法的对象。
当你打印这两个对象时,会输出它们的字符串表示形式。例如:
console.log(obj, obj2); // 输出为 {} {}
这将分别打印出对象 obj
和 obj2
的字符串表示形式,即 {}
。这表示这两个对象都是空对象,因为没有给它们添加任何属性或方法。
自定义构造函数
自定义构造函数是指你可以使用 JavaScript 中的函数来创建自定义对象类型。通过使用构造函数,你可以定义对象的初始状态和行为,并且可以创建该类型的多个实例。
下面是一个简单的示例,展示了如何创建一个自定义的构造函数以及如何使用它来创建对象实例:
function Car() {
this.name = 'BMW'
this.height = 1400
this.width = 4900
this.weight = 1000
}
let car = new Car()
console.log(car);
让我们一行一行地来解释:
function Car() {
这一行代码定义了一个名为 Car
的构造函数,它用于创建代表汽车的对象。
this.name = 'BMW';
this.height = 1400;
this.width = 4900;
this.weight = 1000;
在构造函数内部,通过使用 this
关键字,我们为即将创建的汽车对象设置了几个属性:name
、height
、width
和 weight
。这些属性表示了汽车的名称、高度、宽度和重量。构造函数定义结束。
let car = new Car();
当执行 let car = new Car();
这一行代码时,会发生以下步骤:
- 关键字
new
创建了一个新的对象。 - 构造函数
Car()
被调用,作为对象的初始化函数。 - 在构造函数内部,关键字
this
引用了新创建的对象。 - 构造函数中的代码将属性值分配给对象。在这个例子中,
name
属性被赋值为'BMW'
,height
属性被赋值为1400
,width
属性被赋值为4900
,weight
属性被赋值为1000
。 - 构造函数执行完毕后,返回新创建的对象。
- 新创建的对象被赋值给变量
car
。
最终,car
变量指向了一个具有属性 name
、height
、width
和 weight
的汽车对象。
用代码形式表示:
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);
以上面代码进行拓展:
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:用于包装布尔类型
var obj = {}
obj.a = 1
当你执行 var obj = {}
时,你创建了一个空的对象 obj
。这个对象实际上是一个普通的 JavaScript 对象,它并不是通过包装类创建的。
然后,当你执行 obj.a = 1
时,JavaScript 引擎会根据需要将基本数据类型转换为对应的包装类。在这种情况下,属性 a
被赋予了一个数字值 1,而数字是一种基本数据类型。因此,在给属性 a
赋值时,JavaScript 引擎会将数字 1 隐式地转换为一个 Number 包装对象。
实际上,JavaScript 引擎会在后台执行类似于以下的操作:
obj.a = new Number(1);
这样,属性 a
实际上被赋予了一个包装了数字 1 的 Number 对象。因此,我们可以像操作对象一样操作属性 a
。
隐式包装类操作
隐式包装类操作是指在JavaScript中,当我们对基本数据类型(如字符串、数字和布尔值)进行属性访问或方法调用时,JavaScript引擎会隐式地将基本数据类型转换为对应的包装类对象。这样,我们就可以像操作对象一样操作基本数据类型。
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
。
让我们再看一段代码:
var str = 'abcd'
str.length = 2
console.log(str);
在这段代码中,我们首先创建了一个名为 str
的变量,并将其赋值为字符串 'abcd'
。
接着,我们尝试给 str
这个字符串类型的基本数据添加一个属性 length
,并将其赋值为数字 2
。
然而,与之前提到的类似情况一样,JavaScript 中的字符串是不可变的,它们是原始值,不是对象。当我们尝试给字符串添加属性时,JavaScript 引擎会对这个字符串进行临时的包装(boxing),将其转换为对应的包装类对象(String 对象),然后在这个临时创建的对象上添加属性。
但是,一旦这个表达式结束,这个临时创建的包装类对象就会被丢弃,而我们所添加的属性也会随之消失。因此,尽管我们可以给字符串添加属性,但这些属性并不会被保存下来,因为它们只存在于临时的包装类对象上,而不是原始的字符串上。
所以,最终的输出结果仍然是原始的字符串 'abcd'
,而不是具有新属性的字符串。
如果将上面最后一行输出代码(str)
换成(str.length)
,输出结果将会和本小结第一段代码输出值一样为undefined
。
上面两段代码是原始类型,下面我们看引用类型代码
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
属性的修改确实对数组进行了改变。
以上就是今天的全部内容了,欢迎补充~