JavaScript - 引用类型



JavaScript 引用类型

JavaScript 中有两种类型的数据类型:原始数据类型和引用类型。

原始数据类型是不可变的,这意味着它们无法更改。JavaScript 中的原始数据类型是:Number、String、Boolean、Undefined、Null、Symbol。

引用数据类型是可变的,这意味着它们可以更改。JavaScript 中的参考数据类型为:Object、Array、Function。

将基元数据类型分配给变量时,该变量将获得该值的副本。当您为变量分配引用数据类型时,该变量将获得对该值的引用。这意味着,如果更改 reference 数据类型的值,则更改将反映在引用该值的所有变量中。

例如,下面的代码创建两个变量 x 和 y,并为它们分配值 10:


let x = 10;
let y = 10;

变量 x 和 y 都具有值 10 的副本。如果更改 x 的值,则 y 的值不会更改。


x = 20;
console.log(x); // 20
console.log(y); // 10

下面的代码创建两个变量 x 和 y,并为它们分配一个数组:


const x = [1, 2, 3];
const y = x;

变量 x 和 y 都引用同一个数组。如果更改 x 引用的数组的值,则更改将反映在 y 引用的数组中。


x[0] = 4;
console.log(x); // [4, 2, 3]
console.log(y); // [4, 2, 3]

了解 JavaScript 中基元数据类型和引用数据类型之间的区别非常重要,这样才能编写高效且可预测的代码。

对象和函数是 JavaScript 中的两个主要引用类型,解释如下。

对象

对象是键值对的无序集合,其中键是字符串或符号,值可以是任何数据类型,包括其他对象。


const person = {
	 firstName: "John",
	 lastName: "Doe",
	 age: 30
};

功能

函数也是 JavaScript 中的引用类型。函数是可以调用(调用)来执行任务的特殊类型的对象。


function greet(name) {
	 alert("Hello, " + name + "!");
}

例子

示例 1:对象可变性

在此示例中,我们演示了对象可变性,首先创建一个对象,然后通过该引用进行修改,这反过来又会影响原始对象。person 对象通过来自 anotherPerson 的引用进行修改,恰好是从 25 更改为 30 的年龄。如输出所示,原始对象在修改后发生了变化,因此该对象被称为 mutated。


<!DOCTYPE html>
<html>
<body>
	 	<h2>JavaScript Reference Types Example: Object Mutability</h2>
	 	<script>
	 	 	 // 创建一个对象
	 	 	 const person = {
	 	 	 	 	name: "John",
	 	 	 	 	age: 25
	 	 	 };

	 	 	 // 创建对对象的引用
	 	 	 let anotherPerson = person;

	 	 	 // 显示原始对象
	 	 	 document.write("<p>Original Object: " + JSON.stringify(person) + "</p>");

	 	 	 // 通过引用修改对象
	 	 	 anotherPerson.age = 30;

	 	 	 // 显示修改后的对象
	 	 	 document.write("<p>Modified Object: " + JSON.stringify(person) + "</p>");

	 	 	 // 两个引用都指向同一个对象,因此更改会反映在两者中
	 	 	 document.write("<p>Original Object after modification through reference: " + JSON.stringify(person) + "</p>");
	 	</script>
</body>
</html>

示例 2:数组修改

这里演示了可以在单个变量内的 JavaScript 中存储不同数据类型的多个值的数组。它们表现出可变性,这意味着当对数组进行引用时,对引用所做的更改也会反映在原始数组中。这里我们创建一个 colors 数组,并通过 moreColors 的引用对其进行修改,主要是通过推送一个元素 “yellow”。


<!DOCTYPE html>
<html>
<body>
	 	<h2>JavaScript Reference Types Example: Array Modification</h2>
	 	<script>
	 	 	 // 创建数组
	 	 	 const colors = ["red", "green", "blue"];

	 	 	 // 创建对数组的引用
	 	 	 let moreColors = colors;

	 	 	 // 显示原始阵列
	 	 	 document.write("<p>Original Array: " + JSON.stringify(colors) + "</p>");

	 	 	 // 通过引用修改数组
	 	 	 moreColors.push("yellow");

	 	 	 // 显示修改后的数组
	 	 	 document.write("<p>Modified Array: " + JSON.stringify(colors) + "</p>");

	 	 	 // 两个引用都指向同一个数组,因此更改会反映在两者中
	 	 	 document.write("<p>Original Array after modification through reference: " + JSON.stringify(colors) + "</p>");
	 	</script>
</body>
</html>

示例 3:函数引用类型

在此示例中,我们创建一个函数 greet,其引用最初分配给 greetingFunction。在使用它说 Hello 之后,我们修改引用以指向一个用 Hola 打招呼的不同函数。这展示了 JavaScript 中函数引用的灵活性。


<!DOCTYPE html>
<html>
<body>
	 	<h2>JavaScript Reference Types Example: Function Invocation</h2>
	 	<script>
	 	 	 // 创建一个函数
	 	 	 function greet(name) {
	 	 	 	 	return "Hello, " + name + "!";
	 	 	 }

	 	 	 // 创建对函数的引用
	 	 	 let greetingFunction = greet;

	 	 	 document.write("<p>Original Function Result: " + greetingFunction("John") + "</p>");
	 		
	 	 	 greetingFunction = function(name) {
	 	 	 	 	return "Hola, " + name + "!";
	 	 	 };

	 	 	 document.write("<p>Modified Function Result: " + greetingFunction("Maria") + "</p>");
	 	</script>
</body>
</html>

示例 4:自定义类

这个例子演示了 JavaScript 中的自定义类,从引用类型的角度来看,这是另一个关键方面。该类由属性和函数/方法组成。在这里,我们创建一个带有构造函数和方法的类 Book。创建了此 book 类的 4 个实例,即 (book1、book2、book3、book4),并为其提供相应的数据,例如标题、作者和流派。


<!DOCTYPE html>
<html>
<body>
	 	<h2>JavaScript Reference Types Example: Custom class</h2>
	 	<script>
	 	 	 // 为Book定义自定义类
	 	 	 class Book {
	 	 	 	 	constructor(title, author, genre) {
	 	 	 	 	 	 this.title = title;
	 	 	 	 	 	 this.author = author;
	 	 	 	 	 	 this.genre = genre;
	 	 	 	 	}

	 	 	 	 	// 获取书籍详细信息的方法
	 	 	 	 	getDetails() {
	 	 	 	 	 	 return `Title: ${this.title}<br>Author: ${this.author}<br>Genre: ${this.genre}`;
	 	 	 	 	}
	 	 	 }

	 	 	 // 创建Book类的实例
	 	 	 const book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald", "Fiction");
	 	 	 const book2 = new Book("To Kill a Mockingbird", "Harper Lee", "Classics");
	 	 	 const book3 = new Book("Harry Potter and the Sorcerer's Stone", "J.K. Rowling", "Fantasy");
	 	 	 const book4 = new Book("1984", "George Orwell", "Dystopian Fiction");

	 	 	 document.write("<h3>Book 1 Details:</h3>");
	 	 	 document.write("<p>" + book1.getDetails() + "</p>");

	 	 	 document.write("<h3>Book 2 Details:</h3>");
	 	 	 document.write("<p>" + book2.getDetails() + "</p>");

	 	 	 document.write("<h3>Book 3 Details:</h3>");
	 	 	 document.write("<p>" + book3.getDetails() + "</p>");

	 	 	 document.write("<h3>Book 4 Details:</h3>");
	 	 	 document.write("<p>" + book4.getDetails() + "</p>");
	 	</script>
</body>
</html>

示例 5:不可变对象

此示例侧重于对象的不可变性,这是在创建对象时使用 Object.freeze() 实现的。不可变性基本上意味着对象在创建后不会更改,或者只是确保一旦定义了对象,其属性就无法修改。在这里,我们创建了一个以 name 和 age 作为属性的 person 对象,然后尝试将年龄更改为 35。但是,对象的冻结状态会阻止此修改,并引发错误。不变性是一个重要方面,它有助于维护数据完整性,从而防止意外更改并提高代码执行的可预测性。


<!DOCTYPE html>
<html>
<body>
	 	<h2>Immutable Object with Error Handling</h2>
	 	<script>
	 	 	 // 启用严格模式
	 	 	 'use strict';

	 	 	 // 创建一个不可变对象
	 	 	 const person = Object.freeze({
	 	 	 	 	name: "Alice",
	 	 	 	 	age: 30
	 	 	 });

	 	 	 document.write("<p><strong>Before Modification:</strong></p>");
	 	 	 document.write("<p>Name: " + person.name + "</p>");
	 	 	 document.write("<p>Age: " + person.age + "</p>");

	 	 	 try {
	 	 	 	 	// 尝试修改对象将导致错误
	 	 	 	 	person.age = 35;
	 	 	 } catch (error) {
	 	 	 	 	document.write(error);
	 	 	 }

	 	 	 document.write("<p><strong>After Modification Attempt:</strong></p>");
	 	 	 document.write("<p>Name: " + person.name + "</p>");
	 	 	 document.write("<p>Age: " + person.age + "</p>");
	 	</script>
</body>
</html>