JavaScript 物件導向(Object-oriented programming)入門教學筆記 | 學習筆記
· 閱讀時間約 4 分鐘
1. 物件導向與 new 關鍵字
JavaScript 是基於 原型 (Prototype) 的物件導向語言,而非典型的 類別 (Class) 為基礎的語言。但 ES6 之後,JavaScript 引入了 class 語法,使其更接近傳統的物件導向語言,如 Java 或 C++。
在 JavaScript 中,new 關鍵字用於建立物件,並且會執行以下步驟:
- 建立一個新的空物件。
- 設定該物件的
__proto__指向建構函式 (Constructor) 的prototype。 - 執行建構函式內的程式碼,並將
this綁定到新建立的物件。 - 如果建構函式沒有明確返回物件,則回傳該新物件。
範例:
function Person(name, age) {
this.name = name;
this.age = age;
}
const john = new Person("John", 30);
console.log(john.name); // John
console.log(john.age); // 30
2. __proto__ vs prototype
在 JavaScript 中,__proto__ 和 prototype 是兩個不同的概念。
prototype
prototype 是建構函式的一個屬性,它是一個物件,當我們使用 new 建立物件時,該物件的 __proto__ 會指向 prototype。
範例:
function Animal(name) {
this.name = name;
}
Animal.prototype.sayHello = function() {
console.log("Hello, I am " + this.name);
};
const dog = new Animal("Dog");
dog.sayHello(); // Hello, I am Dog
console.log(dog.__proto__ === Animal.prototype); // true
__proto__
__proto__ 是物件的內部屬性,指向該物件的原型,即 prototype。
範例:
console.log(dog.__proto__); // Animal.prototype
console.log(dog.__proto__.__proto__ === Object.prototype); // true
console.log(dog.__proto__.__proto__.__proto__); // null (最終的原型鏈結束)
關鍵點整理:
prototype是函式的屬性。__proto__是物件的屬性,指向它的prototype。Object.prototype是所有物件的最終原型。
3. class 關鍵字
ES6 之後,JavaScript 引入了 class 語法,使物件導向的寫法更直覺。
定義類別 (Class)
class Car {
constructor(brand) {
this.brand = brand;
}
drive() {
console.log(this.brand + " is driving");
}
}
const myCar = new Car("Toyota");
myCar.drive(); // Toyota is driving
等同於 ES5 的寫法:
function Car(brand) {
this.brand = brand;
}
Car.prototype.drive = function() {
console.log(this.brand + " is driving");
};
優勢:
class提供更簡潔的語法。- 更貼近傳統物件導向語言的語法風格。
constructor方法負責初始化物件。- 方法定義在
prototype上,並不會重複創建。
4. extends 繼承
在 ES6 之前,我們使用 Object.create() 或手動設定 prototype 來實現繼承。
傳統的原型繼承
function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log("Some generic sound");
};
function Dog(name, breed) {
Animal.call(this, name); // 繼承屬性
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype); // 繼承方法
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log("Woof!");
};
const myDog = new Dog("Rex", "Golden Retriever");
myDog.makeSound(); // Some generic sound
myDog.bark(); // Woof!
使用 class 的繼承
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log("Some generic sound");
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 呼叫父類別的 constructor
this.breed = breed;
}
bark() {
console.log("Woof!");
}
}
const myDog = new Dog("Rex", "Golden Retriever");
myDog.makeSound(); // Some generic sound
myDog.bark(); // Woof!
關鍵點:
extends用於建立類別的繼承。super(name)呼叫父類別的constructor,確保this正確初始化。- 子類別可以新增自己的方法。
5. 物件導向開發的最佳實踐
- 使用
class提供更清晰的結構。 - 使用
extends來建立繼承關係,並呼叫super()確保正確初始化。 - 方法定義於
prototype來減少記憶體浪費。 - 理解
__proto__和prototype之間的關係,以便更好地管理原型鏈。 - 避免過度使用繼承,適時使用組合 (Composition) 來降低耦合度。
6. 總結
| 特性 | 傳統原型 (Prototype) | ES6 class |
|---|---|---|
| 建立物件 | new Function() | new Class() |
| 方法定義 | Function.prototype.method = function() {} | 直接定義於 class |
| 繼承 | Object.create() + call() | extends + super() |
this 綁定 | 需要 call() 或 bind() | super() 自動綁定 |
JavaScript 的物件導向概念提供了靈活的方式來組織程式碼,掌握 prototype、class、extends 和 super(),可以幫助開發者寫出更具可讀性與可維護性的程式碼。