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() 函数检查 carItems[] 是否包含您需要移除的商品。如果是,则移除该商品。否则,它会打印一条消息,表明您无法移除该商品。

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.

这样,任何人都无法直接访问和修改 carItems[] 数组。

使用 ES6 类和私有变量实现封装

在 JavaScript 中,您可以使用类和私有变量来实现封装。

JavaScript 中的私有变量(字段)

要定义私有类变量,可以在变量名称后面加上“#”符号。例如,在下面的代码中,“name”是私有变量。

class car {
    #name= "TATA";
}

如果你尝试通过类的实例访问名称,它会给你一个错误,提示私有字段无法在类外部访问。

为了实现封装,你可以在类中定义私有变量,并使用不同的方法让它们访问外部世界。

示例

在下面的示例中,我们定义了汽车类。

汽车类包含“品牌”、“名称”和“里程”三个私有变量。

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

使用 Getter 和 Setter 实现封装

JavaScript 的 getter 和 setter 可以分别使用 get 和 set 关键字定义。getter 用于获取类属性,setter 用于更新类属性。

它们与类方法非常相似,但使用 get/set 关键字后跟方法名进行定义。

示例

在下面的示例中,我们定义了 User 类,其中包含三个名为 username、password 和 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

从以上所有内容,你可以理解封装就是将变量设为私有,并限制其对外部世界的访问。

JavaScript 中封装的优势

这里,我们列出了 JavaScript 中封装的一些好处:

  • 数据保护 - 封装允许你通过将类数据设为私有来控制对它的访问。你只能公开必要的数据和方法。因此,没有人会错误地修改数据。此外,你可以在更新数据时验证它们。如果新数据无效,你可以抛出一个错误。

  • 代码可重用性 - 类是对象的模板,你可以重用它来创建具有不同数据的对象。

  • 代码维护 - 封装使代码易于维护,因为每个对象都是独立的,如果你对一个对象进行更改,它不会影响其他代码。

广告