- Javascript 基础教程
- Javascript - 首页
- JavaScript - 路线图
- JavaScript - 概述
- JavaScript - 特性
- JavaScript - 启用
- JavaScript - 放置
- JavaScript - 语法
- JavaScript - Hello World
- JavaScript - Console.log()
- JavaScript - 注释
- JavaScript - 变量
- JavaScript - let 语句
- JavaScript - 常量
- JavaScript - 数据类型
- JavaScript - 类型转换
- JavaScript - 严格模式
- JavaScript - 保留关键字
- JavaScript 运算符
- JavaScript - 运算符
- JavaScript - 算术运算符
- JavaScript - 比较运算符
- JavaScript - 逻辑运算符
- JavaScript - 按位运算符
- JavaScript - 赋值运算符
- JavaScript - 条件运算符
- JavaScript - typeof 运算符
- JavaScript - 空值合并运算符
- JavaScript - delete 运算符
- JavaScript - 逗号运算符
- JavaScript - 分组运算符
- JavaScript - yield 运算符
- JavaScript - 展开运算符
- JavaScript - 指数运算符
- JavaScript - 运算符优先级
- JavaScript 控制流
- JavaScript - If...Else
- JavaScript - While 循环
- JavaScript - For 循环
- JavaScript - For...in
- Javascript - For...of
- JavaScript - 循环控制
- JavaScript - break 语句
- JavaScript - continue 语句
- JavaScript - Switch Case
- JavaScript - 用户定义迭代器
- JavaScript 函数
- JavaScript - 函数
- JavaScript - 函数表达式
- JavaScript - 函数参数
- JavaScript - 默认参数
- JavaScript - Function() 构造函数
- JavaScript - 函数提升
- JavaScript - 自执行函数
- JavaScript - 箭头函数
- JavaScript - 函数调用
- JavaScript - Function call()
- JavaScript - Function apply()
- JavaScript - Function bind()
- JavaScript - 闭包
- JavaScript - 变量作用域
- JavaScript - 全局变量
- JavaScript - 智能函数参数
- JavaScript 对象
- JavaScript - Number
- JavaScript - Boolean
- JavaScript - Strings
- JavaScript - Arrays
- JavaScript - Date
- JavaScript - DataView
- JavaScript - Handler
- JavaScript - Math
- JavaScript - RegExp
- JavaScript - Symbol
- JavaScript - Sets
- JavaScript - WeakSet
- JavaScript - Maps
- JavaScript - WeakMap
- JavaScript - 可迭代对象
- JavaScript - Reflect
- JavaScript - TypedArray
- JavaScript - 模板字面量
- JavaScript - 带标签的模板
- 面向对象 JavaScript
- JavaScript - 对象
- JavaScript - 类
- JavaScript - 对象属性
- JavaScript - 对象方法
- JavaScript - 静态方法
- JavaScript - 显示对象
- JavaScript - 对象访问器
- JavaScript - 对象构造函数
- JavaScript - 原生原型
- JavaScript - ES5 对象方法
- JavaScript - 封装
- JavaScript - 继承
- JavaScript - 抽象
- JavaScript - 多态
- JavaScript - 解构赋值
- JavaScript - 对象解构
- JavaScript - 数组解构
- JavaScript - 嵌套解构
- JavaScript - 可选链
- JavaScript - 全局对象
- JavaScript - Mixins
- JavaScript - 代理
- JavaScript 版本
- JavaScript - 历史
- JavaScript - 版本
- JavaScript - ES5
- JavaScript - ES6
- ECMAScript 2016
- ECMAScript 2017
- ECMAScript 2018
- ECMAScript 2019
- ECMAScript 2020
- ECMAScript 2021
- ECMAScript 2022
- JavaScript 异步
- JavaScript - 异步
- JavaScript - 回调函数
- JavaScript - Promises
- JavaScript - Async/Await
- JavaScript - 微任务
- JavaScript - Promise 化
- JavaScript - Promises 链式调用
- JavaScript - 定时事件
- JavaScript - setTimeout()
- JavaScript - setInterval()
- JavaScript Cookies
- JavaScript - Cookies
- JavaScript - Cookie 属性
- JavaScript - 删除 Cookies
- JavaScript 浏览器 BOM
- JavaScript - 浏览器对象模型
- JavaScript - Window 对象
- JavaScript - Document 对象
- JavaScript - Screen 对象
- JavaScript - History 对象
- JavaScript - Navigator 对象
- JavaScript - Location 对象
- JavaScript - Console 对象
- JavaScript Web APIs
- JavaScript - Web API
- JavaScript - History API
- JavaScript - Storage API
- JavaScript - Forms API
- JavaScript - Worker API
- JavaScript - Fetch API
- JavaScript - Geolocation API
- JavaScript 事件
- JavaScript - 事件
- JavaScript - DOM 事件
- JavaScript - addEventListener()
- JavaScript - 鼠标事件
- JavaScript - 键盘事件
- JavaScript - 表单事件
- JavaScript - Window/Document 事件
- JavaScript - 事件委托
- JavaScript - 事件冒泡
- JavaScript - 事件捕获
- JavaScript - 自定义事件
- JavaScript 错误处理
- JavaScript - 错误处理
- JavaScript - try...catch
- JavaScript - 调试
- JavaScript - 自定义错误
- JavaScript - 扩展错误
- JavaScript 重要关键字
- JavaScript - this 关键字
- JavaScript - void 关键字
- JavaScript - new 关键字
- JavaScript - var 关键字
- JavaScript HTML DOM
- JavaScript - HTML DOM
- JavaScript - DOM 方法和属性
- JavaScript - DOM Document
- JavaScript - DOM 元素
- JavaScript - DOM 属性 (Attr)
- JavaScript - DOM 表单
- JavaScript - 更改 HTML
- JavaScript - 更改 CSS
- JavaScript - DOM 动画
- JavaScript - DOM 导航
- JavaScript - DOM 集合
- JavaScript - DOM NodeList
- JavaScript - DOM DOMTokenList
- JavaScript 其他
- JavaScript - Ajax
- JavaScript - 异步迭代
- JavaScript - Atomics 对象
- JavaScript - Rest 参数
- JavaScript - 页面重定向
- JavaScript - 对话框
- JavaScript - 页面打印
- JavaScript - 验证
- JavaScript - 动画
- JavaScript - 多媒体
- JavaScript - 图片地图
- JavaScript - 浏览器
- JavaScript - JSON
- JavaScript - 多行字符串
- JavaScript - 日期格式
- JavaScript - 获取日期方法
- JavaScript - 设置日期方法
- JavaScript - 模块
- JavaScript - 动态导入
- JavaScript - BigInt
- JavaScript - Blob
- JavaScript - Unicode
- JavaScript - 浅拷贝
- JavaScript - 调用栈
- JavaScript - 引用类型
- JavaScript - IndexedDB
- JavaScript - Clickjacking 攻击
- JavaScript - 柯里化
- JavaScript - 图形
- JavaScript - Canvas
- JavaScript - 防抖
- JavaScript - 性能
- JavaScript - 样式指南
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 中封装的一些好处:
数据保护 - 封装允许你通过将类数据设为私有来控制对它的访问。你只能公开必要的数据和方法。因此,没有人会错误地修改数据。此外,你可以在更新数据时验证它们。如果新数据无效,你可以抛出一个错误。
代码可重用性 - 类是对象的模板,你可以重用它来创建具有不同数据的对象。
代码维护 - 封装使代码易于维护,因为每个对象都是独立的,如果你对一个对象进行更改,它不会影响其他代码。