js代碼09

題目

好的,我們繼續。

在上一個練習中,我們深入探討了 this 的復雜性。你會發現,ES6 引入的 class 語法在很大程度上就是為了簡化 this 的使用,并為 JavaScript 提供一個更清晰、更熟悉的面向對象編程(OOP)模型。

class 本質上是 JavaScript 現有原型繼承模型的“語法糖”。它沒有改變 JavaScript 的底層機制,但提供了一套非常清晰和友好的語法來創建“對象的藍圖”。


練習 09: 對象的藍圖 - class 語法與面向對象編程

在這個練習中,我們將創建一個 BankAccount 類來模擬一個銀行賬戶,它有自己的屬性(如余額)和方法(如存款、取款)。然后,我們還會創建一個更具體的 SavingsAccount(儲蓄賬戶)類來繼承它。

🎯 學習目標:

  • 學會使用 class 關鍵字定義一個類。
  • 理解并使用 constructor 方法來初始化對象實例的屬性。
  • 在類中定義方法,并理解在這些方法中 this 會自動指向實例對象。
  • 使用 new 關鍵字來創建類的實例。
  • (進階) 使用 extends 關鍵字實現類的繼承。
  • (進階) 在子類中使用 super() 來調用父類的構造函數。

🛠? 任務:

Part 1: 創建一個基礎的 BankAccount

  1. 構造函數 (constructor): 應該接受 ownerName 和一個可選的初始 balance(默認值為 0)作為參數。
  2. deposit(amount) 方法: 增加賬戶余額,并打印一條確認信息。
  3. withdraw(amount) 方法: 減少賬戶余額,但需要檢查余額是否充足。
  4. balance getter: 創建一個名為 balance 的“計算屬性”,用于安全地獲取當前余額。

Part 2 (挑戰): 創建一個 SavingsAccount 子類

  1. 這個類應該繼承BankAccount
  2. 它的 constructor 應該額外接受一個 interestRate (利率) 參數。
  3. 它應該有一個新方法 applyInterest(),用于計算利息并將其存入賬戶。

📋 初始代碼 (09-classes.js):
創建新文件 09-classes.js,并將以下代碼復制進去。你的任務是補全所有 // TODO 的部分。

// --- Part 1: 創建一個基礎的銀行賬戶類 ---
class BankAccount {// 1. 添加一個 constructor// 它應該接受 ownerName 和 balance (默認值為 0)// 為了演示 getter,我們將實際余額存在一個通常表示“私有”的 _balance 變量上。constructor(ownerName, balance = 0) {// TODO: 在這里設置 ownerName 和 _balance 屬性}// 2. 添加 deposit 方法deposit(amount) {// TODO: 增加 _balance 的值,并打印新余額}// 3. 添加 withdraw 方法withdraw(amount) {// TODO: 檢查 _balance 是否足夠,如果足夠則減去金額并打印,否則打印警告}// 4. 使用 getter 來創建一個名為 balance 的只讀屬性get balance() {// TODO: 返回 _balance 的值}
}// --- 使用 BankAccount 類 ---
console.log("--- 操作基礎賬戶 ---");
const myAccount = new BankAccount("Jack", 500);
console.log(`Account created for ${myAccount.ownerName}.`);
// myAccount.deposit(100);
// myAccount.withdraw(200);
// console.log(`Final balance for Jack: ${myAccount.balance}`); // 注意這里是調用 getter,而不是 myAccount._balance
// myAccount.withdraw(500); // 應該會提示余額不足// --- Part 2: (挑戰) 創建一個儲蓄賬戶子類 ---
class SavingsAccount /* TODO: 使用 extends 繼承 BankAccount */ {// 5. 添加 constructor// 它應該接受 ownerName, balance, 和 interestRate。constructor(ownerName, balance = 0, interestRate) {// TODO: 使用 super() 調用父類的構造函數來設置 ownerName 和 balance// TODO: 設置自己的 interestRate 屬性}// 6. 添加 applyInterest 方法applyInterest() {// TODO: 根據 interestRate 計算利息,然后調用父類的 deposit 方法將利息存入。}
}// --- 使用 SavingsAccount 類 ---
console.log("\n--- 操作儲蓄賬戶 ---");
const mySavings = new SavingsAccount("Jill", 1000, 0.05); // 5% 的利率
console.log(`Savings account created for ${mySavings.ownerName}.`);
// mySavings.applyInterest();
// console.log(`Final savings balance for Jill: ${mySavings.balance}`);
// mySavings.withdraw(1100); // 應該會提示余額不足

? 預期輸出:

--- 操作基礎賬戶 ---
Account created for Jack.
New balance: 600
New balance: 400
Final balance for Jack: 400
Insufficient funds! Current balance is 400.--- 操作儲蓄賬戶 ---
Savings account created for Jill.
Interest applied. New balance: 1050
Final savings balance for Jill: 1050
Insufficient funds! Current balance is 1050.

完成這個練習后,你將對如何在 JavaScript 中以結構化的方式創建和管理復雜對象有一個非常清晰的認識。這也是通往所有現代前端框架(它們都大量使用基于類的組件)的必經之路。

答案

好的,我們來看這個 class 練習的完整答案。

這部分代碼集中體現了面向對象編程(OOP)的核心思想:封裝、繼承。

參考實現 (09-classes.js)

// --- Part 1: 創建一個基礎的銀行賬戶類 ---
class BankAccount {// 1. 構造函數:當使用 new 創建實例時,它會被自動調用constructor(ownerName, balance = 0) {// `this` 指向新創建的實例對象this.ownerName = ownerName;// 使用下劃線 `_` 是一種約定,表示這個屬性不應該被外部直接訪問this._balance = balance; }// 2. deposit 方法:類的方法deposit(amount) {if (amount > 0) {this._balance += amount;console.log(`New balance: ${this._balance}`);} else {console.log("Deposit amount must be positive.");}}// 3. withdraw 方法withdraw(amount) {if (amount > this._balance) {console.log(`Insufficient funds! Current balance is ${this._balance}.`);} else if (amount > 0) {this._balance -= amount;console.log(`New balance: ${this._balance}`);} else {console.log("Withdrawal amount must be positive.");}}// 4. getter:它讓我們可以像訪問屬性一樣調用一個函數get balance() {return this._balance;}
}// --- 使用 BankAccount 類 ---
console.log("--- 操作基礎賬戶 ---");
const myAccount = new BankAccount("Jack", 500);
console.log(`Account created for ${myAccount.ownerName}.`);
myAccount.deposit(100);
myAccount.withdraw(200);
// 注意這里我們訪問 .balance,而不是 ._balance。它會自動調用 get balance() 方法。
console.log(`Final balance for Jack: ${myAccount.balance}`);
myAccount.withdraw(500);// --- Part 2: (挑戰) 創建一個儲蓄賬戶子類 ---
// extends 關鍵字用于聲明一個類是另一個類的子類
class SavingsAccount extends BankAccount {// 5. 子類的構造函數constructor(ownerName, balance = 0, interestRate) {// `super()` 必須在子類構造函數中使用 `this` 之前被調用。// 它會調用父類(BankAccount)的構造函數,并傳遞參數。super(ownerName, balance); // 這是子類自己獨有的屬性this.interestRate = interestRate;}// 6. 子類自己獨有的方法applyInterest() {const interest = this._balance * this.interestRate;console.log("Interest applied.");// 調用從父類繼承來的 deposit 方法this.deposit(interest);}
}// --- 使用 SavingsAccount 類 ---
console.log("\n--- 操作儲蓄賬戶 ---");
const mySavings = new SavingsAccount("Jill", 1000, 0.05); // 5% 的利率
console.log(`Savings account created for ${mySavings.ownerName}.`);
mySavings.applyInterest();
console.log(`Final savings balance for Jill: ${mySavings.balance}`);
mySavings.withdraw(1100);

代碼解析

  1. constructor(ownerName, balance = 0)

    • 當你寫 new BankAccount(...) 時,constructor 會被自動執行。
    • this.ownerName = ownerName; 這行代碼是在新創建的實例對象上設置一個名為 ownerName 的屬性。在類的方法中,this 的指向通常就是我們所期望的實例對象,這比之前練習中的情況要簡單得多。
  2. get balance()

    • 這是一個 getter。它定義了一個“訪問器屬性”。從外部看,你可以像讀取普通屬性一樣讀取它(myAccount.balance),但實際上,每次讀取時都會執行這個函數。這是一種封裝的體現——外部只能讀取余額,但不能直接設置 _balance 的值。
  3. class SavingsAccount extends BankAccount

    • extends 關鍵字建立了 SavingsAccountBankAccount 之間的繼承關系。
    • SavingsAccount 自動獲得了 BankAccount 的所有方法(如 deposit, withdraw)和屬性(通過 super 調用設置)。
  4. super(ownerName, balance)

    • 在子類的 constructor 中,super 是一個對父類 constructor 的引用。
    • 必須先調用 super() 來完成父類的初始化工作,然后才能在子類構造函數中使用 this 關鍵字來添加子類自己的屬性(如 this.interestRate)。
  5. 方法繼承 (this.deposit(interest))

    • applyInterest 方法中,我們直接調用了 this.deposit()
    • SavingsAccount 本身沒有定義 deposit 方法,于是 JavaScript 會沿著原型鏈向上查找,在父類 BankAccount 中找到了這個方法,并成功調用。這就是繼承在起作用。

至此,我們已經完整地學習了 JavaScript 語言從基礎到核心的各個重要組成部分:

  • 數據處理(函數式方法)
  • 異步流程(回調、Promise、async/await)
  • 現代語法(解構、展開/剩余)
  • 代碼組織(模塊化)
  • 面向對象thisclass、繼承)

你現在已經擁有了構建復雜 JavaScript 應用程序所需的全部核心知識。無論是去學習 React/Vue/Angular 這樣的前端框架,還是使用 Node.js 構建后端服務,這些知識都是不可或缺的基石。

恭喜你完成了這段系統的學習旅程!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/912676.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/912676.shtml
英文地址,請注明出處:http://en.pswp.cn/news/912676.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于Airtest的App數據爬取實戰:突破傳統爬蟲的邊界

引言:App數據爬取的技術困境 在當今移動優先的時代,App已成為企業核心數據載體,然而??傳統爬蟲技術??在App數據獲取上面臨三大難題: ??協議層屏障??:加密HTTPS、SSL Pinning等技術阻斷中間人攻擊??渲染層障礙??:React Native、Flutter等跨平臺框架使DOM解析…

【LeetCode 熱題 100】560. 和為 K 的子數組——(解法一)前綴和+暴力

Problem: 560. 和為 K 的子數組 題目:給你一個整數數組 nums 和一個整數 k ,請你統計并返回 該數組中和為 k 的子數組的個數 。子數組是數組中元素的連續非空序列。 【LeetCode 熱題 100】560. 和為 K 的子數組——(解法二)前綴和…

android車載開發之HVAC

目前主要在做車載hvac的開發,主要的一些功能主要是hvac,座椅,香氛,設置等的一些模塊,具體模塊下,比如 1.空調 ac,智能模式(極速降溫,極速采暖,智能除味&…

深度學習 Diffusers 庫(自留)

(本文將圍繞 安裝Diffusers庫及其依賴、理解Diffusers核心概念:Pipeline, Model, Scheduler 、使用預訓練模型進行推理(文生圖、圖生圖等) 、 自定義模型和調度器 、訓練自己的擴散模型(可選,需要大量資源&…

【VPC技術】基礎理論篇

文章目錄 概述相關基礎核心知識軟件定義網絡SDNOverlay 技術 安全組概述 參考博客 😊點此到文末驚喜?? 概述 相關基礎 基本概念 虛擬私有云VPC:是一個隔離的網絡環境,每個VPC擁有專屬的IP地址范圍(CIDR)、路由表、…

在 RK3588 Ubuntu 上編譯 eglinfo:全流程實戰 + 常見報錯修復

dv1/eglinfo 是一個開源的 EGL 信息檢測工具,廣泛用于 OpenGL ES 圖形棧調試、驅動驗證和嵌入式平臺圖形支持排查。在 Rockchip RK3588 上編譯該工具可以協助我們確認 EGL DRM 是否配置正確,尤其在無窗口系統(如 eglfs、framebuffer&#xf…

開源推薦:基于前后端分離架構的WMS倉儲管理系統

開源推薦:基于前后端分離架構的WMS倉儲管理系統 🔥 在線演示地址:https://tob.toolxq.com/wms/wms.html 點擊上方鏈接可直接體驗系統功能和界面,無需安裝部署 前言 在企業數字化轉型的浪潮中,倉儲管理系統&#xff08…

Redis中List類型常見的操作命令有哪些?

Redis中List類型是一個字符串列表,這里是一些常見的命令: 1)lpush:將一個或多個值插入到列表頭部。列表不存在,一個新的列表會被創建。 2)rpush:將一個或多個值插入到列表尾部。 3)lpop:移除并返回列表頭…

mac重復文件清理,攝影師同款清理方案

攝影師小林盯著屏幕上的警告:“存儲空間不足”,離截稿只剩3小時。她的MacBook如同塞滿回憶的閣樓,128GB的“其他”空間神秘消失。翻看照片庫時,她驚訝地發現——同一組西藏雪山照片竟有十幾個副本!這是mac重復文件問題…

lua腳本為什么能保證原子性

Redis 處理客戶端請求是基于單線程模型的( Redis 6.0 開始引入了多線程處理網絡 IO,但命令執行仍然是單線程的)。這意味著,在任意時刻 Redis 只會執行一個命令或腳本。這種單線程特性確保了當 Redis 在執行一個 Lua 腳本時&#x…

爬蟲詳解:Aipy打造自動抓取代理工具

一、爬蟲的本質與核心功能 爬蟲是一種通過編寫程序自動抓取互聯網公開數據的技術工具,其核心流程包括: 模擬瀏覽器行為:發送 HTTP 請求訪問目標網頁解析頁面結構:提取 HTML/XML 中的關鍵信息(如文本、鏈接、圖片&…

Leetcode百題斬-棧

終于來到了棧專題,想想之前來阿里的時候就是面試了一道棧最終通過了終面,也是十分懷念了。 739. Daily Temperatures[Medium] 思路:這就是最典型的單調棧問題了。從后向前維護下一個更大值或者下一個更大值的位置。 可以看一下當年面阿里時…

PIXHAWK(ardupilot4.52)NMEA的解析bug

最近在測試過程中發現在橢球高為負的地方,地面站讀取GPS_RAW_INT (24)消息中的alt高度竟然是正值。而消息中定義的alt并不是一個unsigned數據,理論上是帶有正負符號的。 查看gga的原始信息: $GPGGA,063718.40,3714.8533856,N,11845.9411766,…

Linux容器講解以及對應軟件使用

一、容器基礎知識講解 1.1 微服務的部署策略 部署單體應用意味著運行大型應用的多個相同副本,通常提供若干臺(N)服務器(物理機或虛擬 機),在每臺服務器上運行若干個(M)應用實例。部…

企業級應用技術-ELK日志分析系統

目錄 #1.1ELK平臺介紹 1.1.1ELK概述 1.1.2Elasticsearch 1.1.3Logstash 1.1.4Kibana #2.1部署ES群集 2.1.1基本配置 2.1.2安裝Elasticsearch 2.1.3安裝Logstash 2.1.4Filebeat 2.1.5安裝Kibana 1.1ELK平臺介紹 1.1.1ELK概述 ELK 是三個開源工具的縮寫,分別是Elas…

Shiro漏洞復現

Shiro簡介 Apache Shiro是一種功能強大且易于使用的Java安全框架,它執行身份驗證、授權、 加密和會話管理,可用于保護任何應用程序的安全。 Shiro提供了應用程序安全性API來執行以下方面: 1.身份驗證:證明用戶身份,通…

VSCode 中使用 Google Test(GTest)框架測試

VSCode 中使用 Google Test(GTest)框架在 VSCode 中對 C 代碼進行測試的示例: 一、Unbutu x86使用gtest 環境配置 安裝 GTest :在 Ubuntu 系統中,可以通過命令sudo apt-get install libgtest-dev安裝 GTest 庫。對于…

【1.6 漫畫數據庫設計實戰 - 從零開始設計高性能數據庫】

1.6 漫畫數據庫設計實戰 - 從零開始設計高性能數據庫 🎯 學習目標 掌握數據庫表結構設計原則理解字段類型選擇與優化學會雪花算法ID生成策略掌握索引設計與優化技巧了解分庫分表設計方案 📖 故事開始 小明: “老王,我總是不知道怎么設計數…

OSPF虛擬鏈路術語一覽:快速掌握網絡路由

大家好,這里是G-LAB IT實驗室。今天帶大家了解一下OSPF的相關知識! 01 OSPF虛擬鏈路術語大全 網絡架構中,OSPF(開放式最短路徑優先)是一種重要的路由協議。通過其鏈路狀態路由機制,OSPF能夠有效維護和更新…

oracle常用的函數(一) 之 to_char、to_date

文章目錄 前言to_char基本語法格式模型格式模型介紹無FM示例使用FM輸出貨幣負數輸出尖括號 將日期格式化將數字格式化為帶有貨幣符號和千位分隔符的格式總結 to_date語法語法示例 戳這里,第二彈 → oracle常用的函數(二) 之 nvl、decode、l…