Skip to content

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

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

基於類別與基於原型

基於類別的物件導向

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

看看 Java 的程式碼範例:

1. 建立物件藍圖

Java

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

Java

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 建構式 寫法
JavaScript
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
JavaScript
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  makeSound() {
    console.log('The animal makes a sound.');
  }
}

2. 建立物件實體

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

JavaScript
// 創建 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]]

    JavaScript
    console.log(myAnimal)  // 印出可以看到
    Animal {name: ‘Cat’, age: 3}
        age: 3
        name: "doggy"
        [[Prototype]]: Object
              makeSound: ƒ ()
              constructor: f(name, age)
              prototype: {makeSound: ƒ, constructor: ƒ}
              [[Prototype]]: ƒ ()
  • 當對象找不到屬性時,會不斷向上尋找,可以取得原型的屬性跟方法,一層一層形成鏈結,就是原型鏈的由來。

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

    JavaScript
    console.log(myAnimal.__proto__==Animal.prototype);  //true
  • 判斷屬性是否在本身還是原型身上。 語法:obj.hasOwnProperty (屬性名稱)

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

    JavaScript
    console.log(myAnimal instanceof Animal); // true
    console.log(myAnimal instanceof Object); // true
    console.log(myAnimal instanceof Array); // false

回顧總結


網路參考文章