Javascript 是一個物件導向的語言,只不過是基於原型的物件導向,本篇筆記介紹什麼是基於原型的物件導向與原型鏈。
物件導向 Object-oriented programming,縮寫:OOP,是一種設計模式,是使用「物件」來做設計 ,封裝資料與操作,使得程式碼更具重用性與擴展性,易於理解與維護。
基於類別與基於原型
基於類別的物件導向
基於類別 (Class-Based) 的物件導向語言,例如 Java 和 C++。,類別(Class)是物件的抽象設計藍圖,包含資料屬性和操作方法,而物件(Object)是根據類別所創建的具體實例(Instance)。
看看 Java 的程式碼範例:
1. 建立物件藍圖
class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
void makeSound() {
System.out.println("The animal makes a sound.");
}
}
2. 建立物件實體
Main{}是 Java 的主程式入口,使用類別 實例名稱 = new 類別(...)
可以創建不同的物件實體。
public class Main {
public static void main(String[] args) {
// 創建 Animal 類別的實例 myAnimal, ....
Animal myAnimal = new Animal("Dog", 3);
Animal myAnimal2 = new Animal("Cat", 5);
// 呼叫實例的操作方法
myAnimal.makeSound();
System.out.println("Name: " + myAnimal.name);
System.out.println("Age: " + myAnimal.age);
System.out.println("Name: " + myAnimal2.name);
System.out.println("Age: " + myAnimal2.age);
}
}
基於原型的物件導向
基於原型 (Prototype-Based) 的程式語言 JavaScript。只有物件 (Object)以原型物件作為設計藍圖獲得資料屬性和操作方法,沒有傳統類別與實例概念,但類似於建構函式和物件實例。
1. 建立物件藍圖
這邊有兩種寫法,以下看看 ES5 與 ES6 差異,ES6 的寫法更為簡潔。
- ES5 建構式 寫法
var Animal = function (name, age) {
this.name = name;
this.age = age;
};
// 在原型上添加方法 makeSound
// 共享相同方法,節省記憶體。
Animal.prototype.makeSound = function () {
console.log('The animal makes a sound.');
};
- ES6 class 寫法 在 ES2015 有提供 class 關鍵字,但那只是個語法糖,JS 仍然是基於原型的語言。-MDN
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
makeSound() {
console.log('The animal makes a sound.');
}
}
2. 建立物件實體
創建物件實體,使用let 物件名 = new 建構函式(...)
創建。
// 創建 Animal 實例
let myAnimal = new Animal('Cat', 3);
// 使用實例的屬性和方法
console.log(myAnimal.name);
// 輸出: Cat
console.log(myAnimal.age);
// 輸出: 3
myAnimal.makeSound();
// 輸出: The animal makes a sound.
原型鏈
看看由上述程式碼形成的原型鏈:
對象內部的 [[Prototype]]
JavaScriptconsole.log(myAnimal) // 印出可以看到 Animal {name: ‘Cat’, age: 3} age: 3 name: "doggy" [[Prototype]]: Object makeSound: ƒ () constructor: f(name, age) prototype: {makeSound: ƒ, constructor: ƒ} [[Prototype]]: ƒ ()
當對象找不到屬性時,會不斷向上尋找,可以取得原型的屬性跟方法,一層一層形成鏈結,就是原型鏈的由來。
JavaScriptmyAnimal.makeSound();
訪問對象原型 (內部的
[[Prototype]]
) 語法:obj.__proto__
不過這個用法已準備移除,示例先用此表示,建議可改用Object.getPrototypeOf(obj)
JavaScriptconsole.log(myAnimal.__proto__==Animal.prototype); //true
判斷屬性是否在本身還是原型身上。 語法:
obj.hasOwnProperty (屬性名稱)
JavaScriptconsole.log(myAnimal.hasOwnProperty('makeSound')); // false console.log(myAnimal.__proto__.hasOwnProperty('makeSound')); // true
判斷 constructor 構造函數的 prototype 屬性是否在 object 的原型鏈上 語法:
object instanceof constructor
JavaScriptconsole.log(myAnimal instanceof Animal); // true console.log(myAnimal instanceof Object); // true console.log(myAnimal instanceof Array); // false
回顧總結
網路參考文章
- Photo by Mediamodifier on Unsplash