JavaScript - 封装
什么是封装?
JavaScript 中的封装是一种通过捆绑相关属性和方法,将它们保存在单个命名空间下的方法。它可以是函数、类或对象。在 JavaScript 中,封装可以使用闭包、类以及 getter 和 setter 来实现。
封装是面向对象编程语言中的一个基本概念,与继承和多态性并列。JavaScript 是一种面向对象的编程语言。
它用于向外界隐藏数据,并仅允许访问所需数据,以提高数据的完整性和安全性。
为什么需要封装?
让我们通过以下示例讨论 JavaScript 中封装的必要性。
例如,您在代码中定义了以下对象。
const car = {
Brand: "Honda city",
model: "sx",
year: 2016,
}
任何人都可以访问 car 对象的属性,如下所示。
car.Brand
此外,任何人都可以更改 car 对象任何属性的值,如下所示。
car.Brand = true;
此处,Brand 属性的值从字符串更改为布尔值。因此,需要保护对象的原始数据,并限制外部对数据的访问。
在这种情况下,封装的概念应运而生。
在 JavaScript 中实现封装的不同方法
有三种不同的方法可以实现封装。
使用函数闭包
使用 ES6 类
使用 Getter 和 Setter
在这里,我们将逐一学习实现封装的每一种方法。
使用函数闭包实现封装
JavaScript 函数闭包是一种概念,它允许内部函数在外部函数执行后仍然访问其定义的变量。外部函数中定义的变量无法在其函数作用域之外访问,但可以使用内部作用域访问。
示例
在下面的代码中,shoppingCart() 函数是一个包含变量和函数的外部函数。外部函数具有其私有作用域。
carItems[] 数组用于存储购物车中的商品。
add() 函数可以访问 carItems[] 数组并添加商品。
remove() 函数检查 cartItems[] 是否包含需要移除的商品。如果是,则移除该商品。否则,它会打印无法移除该商品的消息。
shoppingCart() 函数返回包含 add() 和 remove() 函数的对象。
创建 shoppingCart() 函数的新实例后,可以使用 add() 和 remove() 函数来操作购物车数据。
<html>
<body>
<p id = "output"> </p>
<script>
let output = document.getElementById("output");
function shoppingCart() {
const cartItems = [];
function add(item) {
cartItems.push(item);
output.innerHTML += `${item.name} added to the cart. <br>`;
}
function remove(itemName) {
const index = cartItems.findIndex(item => item.name === itemName);
if (index !== -1) {
const removedItem = cartItems.splice(index, 1)[0];
output.innerHTML += `${removedItem.name} removed from the cart. <br>`;
} else {
output.innerHTML += `Item ${itemName} not found in the cart. <br>`;
}
}
return {
add,
remove,
};
}
// 定义商品
const item1 = { name: 'Car', price: 1000000 };
const item2 = { name: 'Bike', price: 100000 };
// 创建新的购物车
const cart = shoppingCart();
// 将商品添加到购物车
cart.add(item1);
cart.add(item2);
// 从购物车中移除自行车
cart.remove('Bike');
</script>
</body>
</html>
输出
Car added to the cart. Bike added to the cart. Bike removed from the cart.
这样,任何人都无法直接访问和修改 cartItems[] 数组。
使用 ES6 类和私有变量实现封装
在 JavaScript 中,您可以使用类和私有变量来实现封装。
JavaScript 中的私有变量(字段)
要定义私有类变量,您可以在变量名后跟 # 符号。例如,以下代码中的"name"就是一个私有变量。
class car {
#name= "TATA";
}
如果您尝试通过类的实例访问名称,则会报错,提示私有字段无法在类外部访问。
为了实现封装,您可以在类中定义私有变量,并使用不同的方法让它们被外部访问。
示例
在下面的示例中,我们定义了 car 类。
car 类包含"brand"、"name"和"milage"私有变量。
getMilage() 方法用于返回汽车的里程数,setMilage() 方法用于设置里程数。
我们创建了 car 类的对象,并使用该方法访问和修改私有字段。如果您尝试访问类的私有字段,代码将抛出错误。
您还可以在类中定义更多方法来访问和修改其他私有字段。
<html>
<body>
<div id = "output1">The car mileage is: </div>
<div id = "output2">After updating the car mileage is: </div>
<script>
class Car {
#brand = "TATA"; // Private field
#name = "Nexon"; // Private field
#milage = 16; // Private field
getMilage() {
return this.#milage; // Accessing private field
}
setMilage(milage) {
this.#milage = milage; // Modifying private field
}
}
let carobj = new Car();
document.getElementById("output1").innerHTML += carobj.getMilage();
carobj.setMilage(20);
document.getElementById("output2").innerHTML += carobj.getMilage();
// carobj.#milage); will throw an error.
</script>
</body>
</html>
输出
The car mileage is: 16 After updating the car mileage is: 20
使用 Getter 和 Setter 实现封装
JavaScript 的 getter 和 setter 可以分别使用 get 和 set 关键字定义。getter 用于获取类属性,setter 用于更新类属性。
它们与类方法非常相似,但使用 get/set 关键字加上方法名称来定义。
示例
在下面的示例中,我们定义了 User 类,其中包含三个私有字段,分别为 username、password 和 isLoggedIn。
名为 username 的 getter 和 setter 分别用于获取和设置用户名。在这里,您可以观察到 getters 和 setters 方法的名称是相同的。
之后,我们创建该类的一个对象,并使用 getters 和 setters 作为属性来访问和更新该类的用户名字段。
您也可以为其他类字段创建 getters 和 setters。
<html>
<body>
<div id = "output1">The initial username is: </div>
<div id = "output2">The new username is: </div>
<script>
class User {
#username = "Bob";
#password = "12345678";
#isLoggedIn = false;
get username() {
return this.#username;
}
set username(user) {
this.#username = user;
}
}
const user = new User();
document.getElementById("output1").innerHTML += user.username;
user.username = "Alice";
document.getElementById("output2").innerHTML += user.username;
</script>
</body>
</html>
输出
The initial username is: Bob The new username is: Alice
从以上内容可以理解,封装就是将变量私有化,并限制其对外界的访问。
JavaScript 封装的优势
这里,我们列出了 JavaScript 封装的一些优势 -
数据保护 - 封装允许您通过将类数据设为私有来控制对它们的访问。您只能公开所需的数据和方法。这样,就没有人能够错误地修改数据。此外,您还可以在更新数据时对其进行验证。如果新数据无效,您可以抛出错误。
代码可重用性 − 该类是对象的模板,您可以重用它创建具有不同数据的对象。
代码维护 − 封装使得代码维护变得容易,因为每个对象都是独立的,如果您对一个对象进行更改,不会影响其他代码。

