建構子函數 constructor function 是面向對象編程中的一個重要概念,用於創建和初始化對象。
MDN 文件:物件導向程式設計
建構子函數
建構子函數是一種特殊的函數,用於創建和初始化新對象。
在 JavaScript 中,函數本身可以使用函數來定義對象的屬性和方法,所以可以使用它們來創建建構子函數。
建構子函數的命名慣例是使用大寫字母
開頭,以便區分它們與普通函數,當使用 new
關鍵字來調用建構子函數時,它會返回一個新對象並初始化它。
new
關鍵字 -> 通常建構子函數會與 new
關鍵字一起使用,以便創建新的實例對象。this
代表新創建的對象,可以用 this
來初始化對象的屬性。定義建構子函數
建構子函數的作用是創建新對象並初始化它們。
/**
* Phone 是一個建構子函數,用於創建 Phone 類型的對象
*
* @param {*} make
* @param {*} model
*/
function Phone(make, model) {
this.make = make; // 初始化 make 屬性
this.model = model; // 初始化 model 屬性
}
/**
* 為所有 Phone 實例添加方法
*
*/
Phone.prototype.start = function () {
console.log(`${this.make} ${this.model} is starting.`);
};
new
關鍵字來創建新實例使用 new
關鍵字來調用建構子函數,會進行以下操作:
__proto__
設置為建構子函數的 prototype
。this
指向新創建的對象。this
)。// 創建一個 Phone 的實例
const myPhone = new Phone('Apple', 'iPhone 16 Pro');
// 調用實例方法
myPhone.start(); // Apple iPhone 16 Pro is starting.
🤔 一定要使用 new
嗎?
如果不使用 new
來調用建構子函數,this
會指向全局對象(在瀏覽器中是 window
),這可能會導致錯誤,為了避免這個問題,建構子函數應該總是使用 new
來調用。
const hisPhone = Phone('samsung', 'Galaxy Z Fold6');
// undefined,因為 Phone 函數沒有返回值
console.log(hisPhone);
// samsung,因為 window 調用 Phone,this 就是 window 所以 make, model 都掛在上面
console.log(window.make);
在 ES6 JavaScript 引入了 class
語法,這是一種更清晰的語法來定義類和建構子函數,這對於面向對象編程更直觀,但實際上它仍然基於原型繼承和建構子函數。
依照以上的範例,接下來使用 class
來改寫,可以對應著上方的原始碼與下方的一起看,僅有三個小地方要稍作修改:
function Phone
定義名稱 -> class Phone
constructor ()
內,一個 class 也只能有一個 constructor
。class
內就可以了class Phone {
constructor(make, model) {
this.make = make;
this.model = model;
}
start() {
console.log(`${this.make} ${this.model} is starting.`);
}
}
const myPhone = new Phone('Apple', 'iPhone 16 Pro');
myPhone.start(); // Apple iPhone 16 Pro is starting.
第 4 天:函式 function內容提到提升(hosting),函數因為有提升所以可以先呼叫再寫函數宣告。
console.log(sum(1, 2)); // 3
function sum(x, y) {
return x + y;
}
但是...函數宣告和類別宣告的一個重要差別在於函數宣告是 hosting ,類別宣告則不是;也就是說要先宣告才能呼叫使用,不然會出現錯誤。
資料來源:MDN文件 - Classes
👍🏻👍🏻👍🏻 推薦好片:淺談 Javascript 設計模式 | Alex 宅幹嘛
前一天提到繼承,今天要進入的主題開門就提到物件導向,但是什麼是物件導向呢?
今天就用程式碼說明 OOPs 結束這美好的一天吧!
物件導向 Object-Oriented 是一種程式設計的方法論,它將程式中的資料和相關的操作封裝在一起,以形成稱為物件 Object 的實體。
在物件導向程式設計中,一個物件包含了數據(稱為屬性或狀態)和操作這些數據的方法(稱為方法或行為)。
object 物件
回顧:第 5 天:物件與陣列
物件是 OOP 的基本架構,在 JavaScript 中,class
可以被認為是一種特殊類型的函數,使用建構子可以實例化物件。
class 類
類別是創建物件的藍圖,它們封裝了資料和功能。
class Phone {
constructor(brand, model) {
this.brand = brand;
this.model = model;
}
start() {
console.log(`${this.brand} ${this.model} is starting`);
}
}
const myPhone = new Phone("Apple", "iPhone 16 Pro");
myPhone.start();
Encapsulation 封裝
封裝代表將資料和處理該資料的方法捆綁在單一單元(物件)內,還涉及控制對某些物件組件的存取。
class Car {
// 私有字段,初始化為 0,ES2020(ES11)引入的一個新特性,用來在類內部隱藏數據,使其無法從類外部直接訪問
#mileage = 0;
constructor(brand) {
// 公有字段,初始化為 brand
this.brand = brand;
}
drive(distance) {
// 在類內部修改私有字段
this.#mileage += distance;
}
getMileage() {
// 從類內部讀取私有字段
return this.#mileage;
}
}
const myCar = new Car("Toyota");
myCar.drive(150);
console.log('1', myCar.getMileage());
console.log('2', myCar.#mileage);
Inheritance 繼承
繼承允許一個類別從另一個類別繼承屬性和方法。
class Machine {
constructor(brand) {
// 初始化 brand 屬性
this.brand = brand;
}
start() {
console.log("The machine is starting");
}
}
class Car extends Machine {
constructor(brand, model) {
// 調用父類 Machine 的建構子
super(brand);
// 初始化 model 屬性
this.model = model;
}
}
const myCar = new Car("Lexus", "NX");
console.log(myCar.brand); // Lexus
console.log(myCar.model); // NX
myCar.start(); // The machine is starting
Polymorphism 多態
多態性指的是同一方法名在不同類別中可以有不同的實現。
/**父類別*/
class Machine {
makeSound() {
console.log("Machine sound");
}
}
/**子類別 - Car*/
class Car extends Machine {
makeSound() {
console.log("Honk honk!");
}
}
/**子類別 - Truck*/
class Truck extends Machine {
makeSound() {
console.log("Beep beep!");
}
}
const machines = [new Car(), new Truck()];
machines.forEach((machine) => machine.makeSound());
Abstraction 抽象
抽象化是指只暴露必要的功能接口,而隱藏實現的細節,學後端的歷程中也有遇到這個抽象,真的很抽象。
/** 封裝 */
class Car {
// 初始化 brand 和 model 屬性
constructor(brand, model) {
this.brand = brand;
this.model = model;
}
/** 公共方法,提供了啟動車輛的高級"接口"
* start() 會負責具體實現細節
* 車子引擎運作都是內部方法,車主不需要知道也不用理解
*/
start() {
this.checkFuel();
this.pumpFuel();
this.igniteFuel();
console.log("Car started!"); // 車輛啟動
}
/**
* 這些方法是從車主抽象化出來的
* 屬於內部私有的方法被封裝起來
*/
checkFuel() {
/* 檢查燃料的操作,例如:5油3水 */
}
pumpFuel() {
/* 泵送燃料,加油的操作 */
}
igniteFuel() {
/* 點燃燃料的操作 */
}
}
const myCar = new Car("Lexus", "NX");
myCar.start(); // 車主只需要知道啟動方法
或是用建造一台車子來說明:客戶不需要知道車子怎麼被製造出來的,他只需要從產品目錄表知道有哪些車種,然後就可以下訂單把他開回家!