[重新認識 Javascript 基礎] 什麼是基於原型的物件導向與原型鏈?

Javascript 是一個物件導向的語言,只不過是基於原型的物件導向,本篇筆記介紹什麼是基於原型的物件導向與原型鏈。

目錄 | Contents


物件導向 Object-oriented programming,縮寫:OOP,是一種設計模式,是使用「物件」來做設計 ,封裝資料與操作,使得程式碼更具重用性與擴展性,易於理解與維護。

基於類別與基於原型

基於類別的物件導向

基於類別 (Class-Based) 的物件導向語言,例如 Java 和 C++。,類別(Class)是物件的抽象設計藍圖,包含資料屬性和操作方法,而物件(Object)是根據類別所創建的具體實例(Instance)。

看看 Java 的程式碼範例:

1. 建立物件藍圖

1
2
3
4
5
6
7
8
9
10
11
12

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 類別(...)可以創建不同的物件實體。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

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 建構式 寫法
1
2
3
4
5
6
7
8
9
10
11
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
1
2
3
4
5
6
7
8
9
10
11
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
makeSound() {
console.log('The animal makes a sound.');
}
}


2. 建立物件實體

創建物件實體,使用let 物件名 = new 建構函式(...)創建。

1
2
3
4
5
6
7
8
9
10
11
// 創建 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]]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    console.log(myAnimal)  // 印出可以看到
    Animal {name: ‘Cat’, age: 3}
    age: 3
    name: "doggy"
    [[Prototype]]: Object
    makeSound: ƒ ()
    constructor: f(name, age)
    prototype: {makeSound: ƒ, constructor: ƒ}
    [[Prototype]]: ƒ ()

  • 當對象找不到屬性時,會不斷向上尋找,可以取得原型的屬性跟方法,一層一層形成鏈結,就是原型鏈的由來。

    1
    2
    myAnimal.makeSound();

  • 訪問對象原型 (內部的 [[Prototype]] ) 語法obj.__proto__ 不過這個用法已準備移除,示例先用此表示,建議可改用 Object.getPrototypeOf(obj)

    1
    2
    console.log(myAnimal.__proto__==Animal.prototype);  //true

  • 判斷屬性是否在本身還是原型身上。 語法obj.hasOwnProperty (屬性名稱)

    1
    2
    console.log(myAnimal.hasOwnProperty('makeSound')); // false
    console.log(myAnimal.__proto__.hasOwnProperty('makeSound')); // true
  • 判斷 constructor 構造函數的 prototype 屬性是否在 object 的原型鏈上 語法object instanceof constructor

    1
    2
    3
    console.log(myAnimal instanceof Animal); // true
    console.log(myAnimal instanceof Object); // true
    console.log(myAnimal instanceof Array); // false

回顧總結


網路參考文章

[重新認識 Javascript 基礎] 什麼是基於原型的物件導向與原型鏈?

https://minilabmemo.github.io/2023/02/28/js-03-oop/

作者

Mini Lab Memo

發表於

2023-02-28

更新於

2024-09-26

許可協議

評論