首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau
百百 BLOG
首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau

Kurau Blog

「隨心而寫,真真假假,都是我」

一個記錄生活、輸出興趣的個人空間。
遊戲、影視、閱讀、學習……每一段體驗都值得留下文字。

頁面導覽

  • 學習紀錄
  • 遊戲心得
  • 影視Life
  • 書單
  • 委託作品與二創
  • Kurau
  • 合作邀請

找到我

歡迎來 Discord 找我聊天!

“曾經發生的事不可能忘記,只是暫時想不起來而已。”-《神隱少女》

© 2026 Kurau All rights reserved

程式語言

Class-Based & Prototype-Based

By Kurau·2023-02-07·Updated 2026-05-09·6 分鐘閱讀

Class-Based & Prototype-Based 封面圖

Class-Based vs Prototype-Based

TL;DR
OOP 兩大流派:Class-based(Java / C++ / C#)有「類」跟「實例」清楚二分;Prototype-based(JavaScript)沒有真正的類,所有物件都是「某個原型物件的複製 / 連結」。現代 JS 的 class 語法是 prototype 之上的糖衣,內部仍是 prototype。
主要參考
MDN — Details of the Object Model

兩種流派的本質差別

維度Class-BasedPrototype-Based
代表語言Java / C++ / C# / PythonJavaScript / Self / Lua
物件的「模板」類(Class) — 抽象的類型原型(Prototype) — 是另一個具體物件
創建物件new Class()Object.create(proto)
繼承繼承類(extends)連結原型鏈(__proto__)
編譯期 / 執行期大多 編譯期(static)執行期(dynamic)

Class-Based(Java 範例)

類:抽象的「規格書」(blueprint),不是物件本身。 實例:依規格產生的具體 物件(memory 中的東西)。

// 類:規格書
public class Employee {
    private String name;
    private int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public void giveRaise(int amount) {
        this.salary += amount;
    }
}

// 實例:具體存在的人
Employee victoria = new Employee("Victoria", 50000);
victoria.giveRaise(5000);
java

特性:

  • Victoria 的屬性必定來自 Employee 類的定義
  • 不能臨時加一個 Employee 沒有的屬性(static type 語言會編譯失敗)
  • 結構嚴謹、好維護、IDE 補全強

Prototype-Based(JavaScript)

沒有真正的「類」。所有物件都是 某個其他物件的複製或連結。

// "Prototype" 是個 plain object
const employeePrototype = {
  giveRaise(amount) {
    this.salary += amount;
  },
};

// 從 prototype 建立物件
const victoria = Object.create(employeePrototype);
victoria.name = 'Victoria';
victoria.salary = 50000;
victoria.giveRaise(5000);
javascript

特性:

  • 物件可以 隨時加 / 刪 / 改 屬性
  • 沒有「類定義」這個概念,只有物件之間的 prototype chain
  • 屬性查找順序:自己 → __proto__ → __proto__.__proto__ → ... → null

ES6 class 語法是什麼?

class Employee {
  constructor(name, salary) {
    this.name = name;
    this.salary = salary;
  }
  giveRaise(amount) {
    this.salary += amount;
  }
}

const v = new Employee('Victoria', 50000);
javascript
這只是糖衣
class 在 JS 內部仍然是 prototype-based。Employee 是一個 function,giveRaise 被掛在 Employee.prototype 上。

用 Object.getPrototypeOf(v) === Employee.prototype 驗證。

ES6 加 class 是為了讓 Java / C# 過來的開發者 寫起來自然,但本質沒變。


概念對照(各自怎麼說)

類 vs 物件 / 實例

Class-basedPrototype-based
Class(類)沒對等概念 — 用 prototype object 替代
Instance(實例)Object(物件)
new ClassName()Object.create(proto) 或 new Constructor()

繼承

// Java
class Manager extends Employee { ... }
java
// JS prototype chain
const managerProto = Object.create(employeePrototype);
managerProto.fireEmployee = function (e) { /* ... */ };
const m = Object.create(managerProto);

// JS class syntax(糖衣)
class Manager extends Employee { ... }
javascript

介面(Interface)

Class-basedPrototype-based
有 interface 關鍵字(Java / C# / TS)沒有 interface(只有 duck typing 跟 TypeScript 的 interface)

Duck typing:「走起來像鴨子、叫起來像鴨子,那就是鴨子」 — JS 不檢查型別,只看物件 有沒有需要的方法。

function quack(duck) {
  duck.quack();   // 不管 duck 是什麼類型,只要有 quack() 就 OK
}
javascript

OOP 四大特性(兩種流派都支援)

特性中文兩種流派的實作
Abstraction抽象Class-based: abstract class / Prototype: 用 plain object
Encapsulation封裝private / public / TS / # 私有欄位
Inheritance繼承extends / prototype chain
Polymorphism多型兩者都支援(覆寫方法)

變數範圍(Java 為例)

public class Container {
    static int classVar = 0;        // 類變數(所有實例共享)
    int instanceVar = 0;            // 實例變數(每個實例獨立)

    void method() {
        int localVar = 0;           // 區域變數
    }
}
java

重點:

  • static 變數 是 全類唯一份,改一個實例會影響全部
  • instance 變數 是 每個物件各自一份
  • final 變數 是 不可變(常數)
class Test {
    static int iValue = 0;
}

public class Main {
    public static void main(String[] args) {
        Test t1 = new Test();
        Test t2 = new Test();
        System.out.println(t1.iValue);   // 0
        t2.iValue = 10;
        System.out.println(t1.iValue);   // ⚠️ 也變 10!(static 共享)
    }
}
java

Java 檔名規則(easy to forget)

// Account.java(檔名跟 public class 同名)
public class Account {
    // 實作
}

// 一個檔案 ==只能有一個 public class==
class SomeOtherClass {
    // OK,這個不是 public
}
java

規則:

  • public class 必須跟檔名同名,且每個檔案最多一個 public class
  • 不是 public 的 class 在 compile 後會生成獨立 .class 檔
  • 執行時用 class 名稱(不是 .java 檔名)

為什麼 JS 走 prototype-based?

設計者 Brendan Eich 1995 年寫 JS 時 受 Self / Scheme 影響:

  • 靈活:物件可隨時改造
  • 簡單:不需要 class 機制,只需要 object + reference
  • delegation:沒有的方法自動往上找

代價:

  • 入門者看到「沒有 class 」很困惑
  • 易出錯(隨手改 prototype 影響全 app)
  • ES6 加 class 糖衣 補救

現代 TypeScript 同時擁有兩者

// Class-based 風格(TS 強型別)
class Employee {
  constructor(public name: string, public salary: number) {}
  giveRaise(amount: number) { this.salary += amount; }
}

// 介面(structural typing,duck typing 強化版)
interface Quackable {
  quack(): void;
}

function makeNoise(thing: Quackable) {
  thing.quack();
}

// 任何有 quack() 的物件都行,不用 implements
makeNoise({ quack: () => console.log('quack!') });
typescript

TypeScript 的 interface 是 structural — 看 結構符不符合,不看 是否 explicitly implements。比 Java 的 nominal typing 彈性。

目錄

    ◆ 相關文章

    • Java SE 6 技術手冊

      2026-05-09
    • JavaScript 浮點數問題

      2026-05-09
    • Python Self learning

      2026-05-09
    • tsx 轉 jsx

      2026-05-09
    ← 上一篇Java SE 6 技術手冊下一篇 →Class Components 介紹

    ◆ 關於作者

    Kurau

    個人寫作 / 創作的 SoT,記錄遊戲、影視、學習與生活。

    更多 Kurau 的文章