
- 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 中封裝的一些好處:
資料保護 - 封裝允許你透過將類資料設為私有來控制對它的訪問。你只能公開必要的資料和方法。因此,沒有人會錯誤地修改資料。此外,你可以在更新資料時驗證它們。如果新資料無效,你可以丟擲一個錯誤。
程式碼可重用性 - 類是物件的模板,你可以重用它來建立具有不同資料的物件。
程式碼維護 - 封裝使程式碼易於維護,因為每個物件都是獨立的,如果你對一個物件進行更改,它不會影響其他程式碼。