Javascript 简明教程
JavaScript - Encapsulation
What is Encapsulation?
JavaScript 中的封装是一种通过捆绑相关属性和方法到单个命名空间下,来保持这些属性和方法的私有性。它可以是函数、类或对象。在 JavaScript 中,可以使用闭包、类及访问器和设置器实现封装。
封装是面向对象编程语言中的一个基本概念,连同继承和多态性。JavaScript 是一种面向对象的编程语言。
它用于隐藏数据,避免外界访问,仅向需要的数据提供访问权限,从而提高数据的完整性和安全性。
What is the need for encapsulation?
让我们通过以下示例讨论在 JavaScript 中封装的必要性。
例如,你在代码中定义了以下对象。
const car = {
Brand: "Honda city",
model: "sx",
year: 2016,
}
如下所示,任何人都可以访问 car 对象的属性。
car.Brand
此外,如下所示,任何人都可以更改 car 对象的任何属性的值。
car.Brand = true;
此处,Brand 属性的值从字符串更改为布尔。因此,需要保护对象的原始数据,并限制外部世界对数据的访问。
在这种情况下,封装的概念进入了画面。
Different Ways to Achieve Encapsulation in JavaScript
有三种不同的方法来实现封装。
-
Using the function closures
-
Using the ES6 classes
-
使用 getter 和 setter
此处,我们将逐一学习每种实现封装的方法。
Achieving Encapsulation Using the Function Closures
JavaScript 函数闭包是一个允许内部函数访问外部函数中定义的变量的概念,即使在执行了外部函数之后也是如此。在外部函数中定义的变量不能在其功能范围之外访问,但可以使用内部范围访问。
Example
在以下代码中,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,
};
}
// Defining items
const item1 = { name: 'Car', price: 1000000 };
const item2 = { name: 'Bike', price: 100000 };
// Create a new Shopping cart
const cart = shoppingCart();
// Adding items to the cart
cart.add(item1);
cart.add(item2);
// Remove bike from the cart
cart.remove('Bike');
</script>
</body>
</html>
Car added to the cart.
Bike added to the cart.
Bike removed from the cart.
通过这种方式,没有人可以直接访问和修改 cartItem[] 数组。
Achieving Encapsulation Using ES6 Classes and Private Variables
在 JavaScript 中,您可以使用类和私有变量来实现封装。
Private Variables (Fields) in JavaScript
要定义私有类变量,您可以在变量名前面写“#”符号。例如,“name”是以下代码中的私有变量。
class car {
#name= "TATA";
}
如果您尝试通过类的实例访问 name,它将给您一个错误,指出类外部无法访问私有字段。
要实现封装,可以在类中定义私有变量,并使用不同的方法授予它们对外部世界的访问。
Example
在下方的示例中,我们定义了汽车类。
汽车类包含 "品牌"、"名称" 和 "英里数" 私有变量。
定义 getMilage() 方法可返回汽车的英里数, 而 setMilage() 方法用来设置汽车英里数。
我们创建了汽车类的对象,并用方法访问和修改私有字段。如果你试图访问类的私有字段,代码将抛出一个错误。
你也可以定义类中的更多方法来访问和修改其他私有字段。
<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
Achieving Encapsulation Using the Getters and Setters
JavaScript 的 getter 和 setter 可以分别使用 get 和 set 关键字定义。getter 用于获取类属性,而 setter 用于更新类属性。
它们和类方法非常相似,但使用 get/set 关键字后跟方法名定义。
Example
在下面的示例中,我们定义了 User 类,其中包含三个私有字段,分别为用户名、密码和 isLoggedIn。
定义了名为 username 的 getter 和 setter 用于获取和设置用户名。在这里,你可以观察到 getter 和 setter 方法的名称是相同的。
之后,我们创建一个类的对象,并将 getter 和 setter 作为属性用于访问和更新类的 username 字段。
你也可以为其他类字段创建 getter 和 setter。
<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
从上述所有内容,你可以理解封装使变量变为私有的,并限制其对外部世界的访问。