🔥連接:https://www.subham.online

🔥回購:https://github.com/Subham-Maity/OOPS-in-JS-Ultimate

🔥推特:https://twitter.com/TheSubhamMaity


▶️簡介

⭐ 什麼是物件導向程式設計?

物件導向程式設計是一種透過建立物件來解決問題的方法。

⭐ OOP 的 4 支柱

OOP 中的術語

  1. 抽象- 隱藏內部細節(僅顯示基本資訊!)

  2. 封裝- 將各種元件放在一起(在膠囊中)的行為

  3. 繼承-從現有事物中衍生出新事物的行為

  4. 多態性-一個實體,多種形式

js

▶️原型與原型

JavaScript 的物件有一個稱為prototype的特殊屬性,它要麼為null ,要麼引用另一個物件

當我們嘗試從物件中讀取屬性而該屬性遺失時,JavaScript 會自動從原型中取得該屬性。這稱為原型繼承

⭐ 設定原型

我們可以透過設定__proto__來設定原型。如果我們從一個物件中讀取一個不在該物件中但存在於原型中的屬性,JavaScript 將從原型中取得它。如果我們在物件中有一個方法,它將從該物件中呼叫。如果物件中缺少它但存在於原型中,則會從原型中呼叫它。

⭐ 範例:

//It will work properly
let p = {
    run : () => {
        console.log("run")
    }
}

p.run()//Output: - run

//Let's define another property
let a = {
    name : " subham"
}

a.run() //TypeError: a.run is not a function

//Now with proto
let b = {
    name : " subham"
}
b.__proto__ = p
b.run() //Output: - run

簡單地說,您可以在另一個物件中繼承某個物件的原型。這稱為原型繼承。

//It will work properly
let p = {
    run : () => {
        console.log("p run")
    }
}

p.run()//Output: - p run

//Now with proto
let b = {
    run : () => {
        console.log("b run")
    }
}
b.__proto__ = p
b.run() //Output: - b run

如果物件中已存在屬性或方法,JavaScript 將使用該屬性或方法。如果它不存在於物件中但存在於原型中,JavaScript 將從原型中獲取它。在此範例中,由於b物件中已存在run方法,因此它將列印“b run”。

▶️ 類別和物件

  • 在物件導向程式設計中,類別是特定類型物件中方法和變數的範本定義

  • 在物件導向程式設計中,物件是已在記憶體中分配的類別(或結構)的特定實例。

⭐ 範例:

//class
class GoogleForm {
    submit() {
       console.log(this.name + " " + this.roll + " Your form submitted")
    }
    cancel() {
        console.log(this.name + " " + this.roll +" Your form cancelled")
    }
    fill(given_name , roll) {
        this.name = given_name
        this.roll = roll
    }
}

//object
const student1Form = new GoogleForm()

student1Form.fill("Rahul" , 24)

const student2Form = new GoogleForm()

student2Form.fill("Raj" , 25)

student2Form.cancel()

student1Form.submit()

student2Form.submit()

▶️構造函數

在 JavaScript 中,建構函數是一個特殊的函數,它會建立和初始化物件,設定它們的初始狀態和屬性。

假設他們忘記填寫表格並點擊提交按鈕,則會拋出未定義的錯誤!

class Form {

    submit() {
        console.log(this.name + ": Your form is submitted for train number: " + this.trainno)
    }

    cancel() {
        console.log(this.name + ": This form is cancelled for train number: " + this.trainno)
        this.trainno = 0
    }
    fill(givenname, trainno) {
        this.name = givenname
        this.trainno = trainno
    }

}

let myForm1 = new Form()

let myForm2 = new Form()
//
// myForm1.fill("Gaurav", 1234)
//
// myForm2.fill("Rahul", 5678)

myForm1.submit()

myForm2.submit()

myForm2.cancel()

// Output: undefined: Your form is submitted for train number: undefined
// Output: undefined: Your form is submitted for train number: undefined
// Output: undefined: This form is cancelled for train number: undefined

現在建立建構函數,

class Form {

    constructor() {
        this.name = "Gaurav"
        this.trainno = 0
    }

    submit() {
        console.log(this.name + ": Your form is submitted for train number: " + this.trainno)
    }

    cancel() {
        console.log(this.name + ": This form is cancelled for train number: " + this.trainno)
        this.trainno = 0
    }
    fill(givenname, trainno) {
        this.name = givenname
        this.trainno = trainno
    }

}

let myForm1 = new Form()

let myForm2 = new Form()

// myForm1.fill("Gaurav", 1234)
//
// myForm2.fill("Rahul", 5678)

myForm1.submit()

myForm2.submit()

myForm2.cancel()

// Output: Gaurav: Your form is submitted for train number: 0
// Output: Gaurav: Your form is submitted for train number: 0
// Output: Gaurav: This form is cancelled for train number: 0

⭐ 構造函數的型別

  1. 非參數化建構函數:沒有參數的建構子。
    class Example {
        constructor() {
            this.property = "default value";
        }
    }
  1. 參數化建構函數:帶有參數的建構子。
    class Example {
        constructor(value) {
            this.property = value;
        }
    }
  1. 複製建構子:JavaScript 沒有像 C++ 或 Java 那樣的內建複製建構子。但是,您可以建立一個方法來複製物件。
    class Example {
        constructor(value) {
            this.property = value;
        }

        copy() {
            return new Example(this.property);
        }
    }

    const original = new Example("original value");
    const copy = original.copy();

與 C++ 等語言不同,JavaScript 沒有析構函數。相反,JavaScript 依賴自動釋放記憶體的高效垃圾收集器。

▶️傳承

一個類別從另一個類別派生屬性和特徵的能力稱為繼承。

⭐ 為什麼?

如果你不知道什麼是繼承

class Animal {
    constructor(name, color , age) {
        this.name = name
        this.color = color
        this.age = age
    }
    run() {
        console.log(this.name + ' is running')
    }

    shout() {

        console.log(this.name + ' is shouting')
    }

    sleep() {
        console.log(this.name + ' is sleeping')
    }
}

//If you are nub developer you will do
class Monkey {
    constructor(name, color) {
        this.name = name
        this.color = color
    }
    run() {
        console.log(this.name + ' is running')
    }

    shout() {

        console.log(this.name + ' is shouting')
    }

    sleep() {
        console.log(this.name + ' is sleeping')
    }

    eatBanana() {
        console.log(this.name + ' is eating banana')
    }
}

const animal_1 = new Monkey('Simba monkey', 'Brown', 2)

const animal_2 = new Animal('Donkey', 'White', 3)

animal_1.eatBanana()

animal_2.shout()

如果你知道

//Parent Class - Base Class
class Animal {
    constructor(name, color , age) {
        this.name = name
        this.color = color
        this.age = age
    }
    run() {
        console.log(this.name + ' is running')
    }

    shout() {

        console.log(this.name + ' is shouting')
    }

    sleep() {
        console.log(this.name + ' is sleeping')
    }
}

//Child Class - Derived Class
class Monkey extends Animal{
    eatBanana() {
        console.log(this.name + ' is eating banana')
    }
    //you can also add new methods
    hide() {
        console.log(this.name + ' is hiding')
    }
}

const animal_1 = new Monkey('Simba monkey', 'Brown', 2)

const animal_2 = new Animal('Donkey', 'White', 3)

animal_1.eatBanana()
animal_1.run()
animal_1.hide()

animal_2.shout()

⭐ 繼承型

  1. 單級繼承 當一個類別繼承另一個類別時,稱為單級繼承。
class Shape {
  area() {
    console.log("Displays Area of Shape");
  }
}

class Triangle extends Shape {
  area(h, b) {
    console.log((1/2) * b * h);
  }
}

const triangle = new Triangle();
triangle.area(10, 5); // Output: 25
  1. 分層繼承被定義為從基底類別派生多個類別的過程。
class Shape {
  area() {
    console.log("Displays Area of Shape");
  }
}

class Triangle extends Shape {
  area(h, b) {
    console.log((1/2) * b * h);
  }
}

class Circle extends Shape {
  area(r) {
    console.log(3.14 * r * r);
  }
}

const triangle = new Triangle();
triangle.area(10, 5); // Output: 25

const circle = new Circle();
circle.area(7); // Output: 153.86
  1. 多級繼承是從一個衍生類別派生另一個類別的過程。
class Shape {
  area() {
    console.log("Displays Area of Shape");
  }
}

class Triangle extends Shape {
  area(h, b) {
    console.log((1/2) * b * h);
  }
}

class EquilateralTriangle extends Triangle {
  constructor(side) {
    super();
    this.side = side;
  }

  area() {
    console.log((Math.sqrt(3) / 4) * this.side * this.side);
  }
}

const equilateralTriangle = new EquilateralTriangle(5);
equilateralTriangle.area(); // Output: 10.825317547305486
  1. 混合繼承是簡單繼承、多重繼承和層次繼承的結合。 JavaScript 不會直接支援多重繼承,但我們可以使用 mixins 實作類似的行為。
class Shape {
  area() {
    console.log("Displays Area of Shape");
  }
}

class Triangle extends Shape {
  area(h, b) {
    console.log((1/2) * b * h);
  }
}

class Circle extends Shape {
  area(r) {
    console.log(3.14 * r * r);
  }
}

const mixin = (Base) => class extends Base {
  perimeter() {
    console.log("Calculates Perimeter");
  }
};

class EquilateralTriangle extends mixin(Triangle) {
  constructor(side) {
    super();
    this.side = side;
  }

  area() {
    console.log((Math.sqrt(3) / 4) * this.side * this.side);
  }
}

const equilateralTriangle = new EquilateralTriangle(5);
equilateralTriangle.area(); // Output: 10.825317547305486
equilateralTriangle.perimeter(); // Output: Calculates Perimeter

▶️ 方法重寫

如果在超類別和子類別中都定義了相同的方法,那麼子類別的方法就會覆寫超類別的方法

  • 一般的
class human {
    constructor(name , age , body_type) {
        this.name = name
        this.age = age
        this.body_type = body_type
    }

    getName() {
        console.log("The name of the human is : ", this.name)
    }

    getAge() {

        console.log("The age of the human is :", this.age)
    }

    getBodyType() {
        console.log("The body type of the human is :", this.body_type)
    }
}

class student extends human {}

const student_1 = new student("Subham" , 24 , "Thin")

student_1.getAge() //The age of the human is : 24

⭐ 超級關鍵字 - 類型

super關鍵字用於呼叫父類別的建構子來存取其屬性和方法。

重寫構造函數

class Human {
    constructor(name, age, bodyType) {
        this.name = name;
        this.age = age;
        this.bodyType = bodyType;
    }

    getName() {
        console.log("The name of the human is:", this.name);
    }

    getAge() {
        console.log("The age of the human is:", this.age);
    }

    getBodyType() {
        console.log("The body type of the human is:", this.bodyType);
    }
}

class Student extends Human {
    constructor() {
        super("Rahul", 80, "Fat");
    }
}

const student1 = new Student();

student1.getName(); // The name of the human is: Rahul

重寫方法

class Human {
    constructor(name, age, bodyType) {
        this.name = name;
        this.age = age;
        this.bodyType = bodyType;
    }

    getName() {
        console.log("The name of the human is:", this.name);
    }

    getAge() {
        console.log("The age of the human is:", this.age);
    }

    getBodyType() {
        console.log("The body type of the human is:", this.bodyType);
    }
}

class Student extends Human {
    constructor() {
        super("Rahul", 80, "Fat");
    }

    // Overriding using super keyword in child class
    getAge() {
        super.getAge();
        console.log("The age of the student is:", 20);
    }
}

const student1 = new Student();

student1.getAge(); // The age of the human is: 80
                   // The age of the student is: 20

⭐ 方法重寫重點

  1. 方法名稱相同:子類別中的方法必須與父類別中的方法名稱相同。

  2. 參數相同:子類別中的方法必須與父類別方法具有相同的參數清單。

  3. IS-A 關係:方法重寫僅發生在具有 IS-A 關係(繼承)的兩個類別中。

  4. 存取修飾符:重寫方法可以具有限制較少的存取修飾符,但不能具有限制較多的存取修飾符。

  5. Super 關鍵字:您可以使用super關鍵字從父類別呼叫重寫的方法。

⭐ 附註

註1

class human {
    constructor() {
        console.log("Human class constructor")
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
}
const student_1 = new student()
student_1.eat()

//Human class constructor
// Human can eat

如果您沒有在子類別中明確定義建構函數,JavaScript 會自動為您建立一個使用 super() 呼叫父類別建構函數的建構子。

像這樣

class human {
    constructor() {
        console.log("Human class constructor")
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
    constructor(...arg) {
        super(...arg);
    }
}
const student_1 = new student()
student_1.eat()

註2

class human {
    constructor() {
        console.log("Human class constructor")
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
    constructor() {
        console.log("This is student class constructor")
    }
}
const student_1 = new student()
student_1.eat()

// console.log("This is student class constructor")
//ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

你必須像這樣使用 super 關鍵字

class human {
    constructor() {
        console.log("Human class constructor")
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
    constructor() {
        super()
        console.log("This is student class constructor")
    }
}
const student_1 = new student()
student_1.eat()

註3

class human {
    constructor(name) {
        console.log("Human class constructor" , name)
        this.name = name
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
    constructor(name) {
        this.name = name //not allow
        super()
        console.log("Student class constructor" , name)

    }
}
const student_1 = new student("subham")
student_1.eat()

// this.name = name
// ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

在 super 關鍵字之後你可以使用這個

class human {
    constructor(name) {
        console.log("Human class constructor" , name)
        this.name = name
    }
    eat() {
        console.log("Human can eat")
    }
}
class student extends human {
    constructor(name) {
        super()
        this.name = name
        console.log("Student class constructor" , name)

    }
}
const student_1 = new student("subham")
student_1.eat()

// Human class constructor undefined
// Student class constructor subham
// Human can eat

▶️方法重載

類別中有兩個或多個具有相同名稱和不同參數的方法(或函數)

⭐ 我們可以在 JavaScript 中重載函數嗎?

在 JavaScript 中,本機不支援某些其他語言(如 Java)中的方法重載。這意味著您不能在同一個類別中定義多個具有相同名稱但參數不同的方法。但是,您可以使用檢查單一方法中參數的數量和類型等技術來實現類似的功能。

你不能在 JS 中這樣做

class Calculator {
    add(a, b) {
        return a + b;
    }

    add(a, b, c) {
        return a + b + c;
    }
}

const calc = new Calculator();
console.log(calc.add(1, 2)); // This will throw an error because the first add method is overwritten

如果你願意,你可以透過這樣做來實現

class Calculator {
    add(...args) {
        if (args.length === 2) {
            return args[0] + args[1];
        } else if (args.length === 3) {
            return args[0] + args[1] + args[2];
        } else {
            throw new Error("Invalid number of arguments");
        }
    }
}

const calc = new Calculator();

console.log(calc.add(1, 2)); // Output: 3
console.log(calc.add(1, 2, 3)); // Output: 6

▶️ 存取修飾符

存取修飾符是一個關鍵字,用於設定類別成員的可存取性

⭐ 存取修飾符的類型

  1. Public :聲明為 public 的成員可以從任何其他類別存取。

  2. Protected :宣告為 protected 的成員可以在同一類別中和衍生類別實例中存取。

  3. Private :宣告為私有的成員只能在同一個類別中存取。

⭐ 無障礙桌

|修改器|家長課 |兒童班|課外|

|----------------|------------|-------------|--- - ------------|

|公共| ✔️ | ✔️ | ✔️ |

|受保護| ✔️ | ✔️ | ❌ |

|私人| ✔️ | ❌ | ❌ |

⭐ 範例

1. 公眾會員

公共成員可以從任何地方存取。

class Parent {
    publicProperty = "I'm public";

    publicMethod() {
        return "This is a public method";
    }
}

class Child extends Parent {
    useParentPublic() {
        console.log(this.publicProperty);
        console.log(this.publicMethod());
    }
}

const parent = new Parent();
const child = new Child();

console.log(parent.publicProperty);  // Output: I'm public
console.log(parent.publicMethod());  // Output: This is a public method
child.useParentPublic();
// Output: 
// I'm public
// This is a public method

在此範例中,可以從下列位置存取publicPropertypublicMethod

  • 在父類別中

  • 在Child類別中

  • 任何班級之外

2. 受保護會員(模擬)

在 JavaScript 中,我們按照慣例使用下劃線前綴來表示受保護的成員。從技術上講,它們仍然是公開的,但開發人員同意不直接在類別或其子類別之外存取它們。

class Parent {
    _protectedProperty = "I'm protected";

    _protectedMethod() {
        return "This is a protected method";
    }
}

class Child extends Parent {
    useParentProtected() {
        console.log(this._protectedProperty);
        console.log(this._protectedMethod());
    }
}

const parent = new Parent();
const child = new Child();

child.useParentProtected();
// Output:
// I'm protected
// This is a protected method

// These work, but violate the convention:
console.log(parent._protectedProperty);
console.log(parent._protectedMethod());

在這種情況下:

  • _protectedProperty_protectedMethod可在 Parent 內存取

  • 它們也可以在 Child 中存取(繼承)

  • 從技術上講,它們可以在外部存取,但這違反了約定

3. 私人會員

私有成員是真正私有的,只能在定義它們的類別中存取。

class Parent {
    #privateProperty = "I'm private";

    #privateMethod() {
        return "This is a private method";
    }

    usePrivate() {
        console.log(this.#privateProperty);
        console.log(this.#privateMethod());
    }
}

class Child extends Parent {
    tryToUseParentPrivate() {
        // These would cause errors if uncommented:
        // console.log(this.#privateProperty);
        // console.log(this.#privateMethod());
    }
}

const parent = new Parent();
const child = new Child();

parent.usePrivate();
// Output:
// I'm private
// This is a private method

// These would cause errors:
// console.log(parent.#privateProperty);
// console.log(parent.#privateMethod());
// child.tryToUseParentPrivate();

在這種情況下:

  • #privateProperty#privateMethod只能在 Parent 內存取

  • 即使它擴展了父級,它們也無法在子級中存取

  • 在課堂之外根本無法存取它們

重點

  1. 公共成員(預設)可以在任何地方存取。

  2. 受保護的成員(使用_的約定)可以在類別和子類別內存取,但不應在外部存取(儘管從技術上講是可以的)。

  3. 私有成員(帶有# )只能在定義類別中存取,不能在子類別中或外部存取。

  4. 使用受保護成員時,它們在可存取性方面的行為與公共成員類似,但開發人員同意將它們視為受保護的成員。

  5. 真正的隱私和封裝只能透過使用#語法的私有成員來實現。

▶️靜態

static 關鍵字定義類別的靜態方法或字段

靜態方法是屬於類別本身的方法,而不屬於該類別的任何特定實例。

class Animal {
    constructor(name) {
        this.name = Animal.capitalize(name);
    }

    static capitalize(name) {
        return name.charAt(0).toUpperCase() + name.slice(1);
    }

    walk() {
        console.log(`Animal ${this.name} is walking`);
    }
}

const animal = new Animal("lion");
animal.walk(); // Output: Animal Lion is walking

console.log(Animal.capitalize("elephant")); // Output: Elephant

要點:

  1. 使用static關鍵字將capitalize方法宣告為靜態方法。

  2. 它是在類別( Animal.capitalize )上呼叫的,而不是在實例上呼叫的。

  3. 它可以在建構函式或其他使用類別名稱的方法中使用。

⭐ 繼承和靜態方法

靜態方法由子類別繼承:

class Human extends Animal {
    static greet() {
        console.log("Hello!");
    }
}

const human = new Human("john");
human.walk(); // Output: Animal John is walking

console.log(Human.capitalize("sarah")); // Output: Sarah
Human.greet(); // Output: Hello!

筆記:

  1. Human類別繼承了Animal的靜態capitalize方法。

  2. Human也可以定義自己的靜態方法,例如greet

⭐ 從非靜態方法呼叫靜態方法

您可以從非靜態方法呼叫靜態方法,但需要使用類別名稱:

class Calculator {
    static add(a, b) {
        return a + b;
    }

    multiply(a, b) {
        // Using a static method in a non-static method
        return Calculator.add(a, 0) * b;
    }
}

const calc = new Calculator();
console.log(calc.multiply(3, 4)); // Output: 12
console.log(Calculator.add(5, 6)); // Output: 11

⭐ 靜態方法與實例方法

下面透過比較來說明差異:

class MyClass {
    static staticMethod() {
        return "I'm a static method";
    }

    instanceMethod() {
        return "I'm an instance method";
    }
}

console.log(MyClass.staticMethod()); // Output: I'm a static method

const obj = new MyClass();
console.log(obj.instanceMethod()); // Output: I'm an instance method

// This would throw an error:
// console.log(MyClass.instanceMethod());

// This would also throw an error:
// console.log(obj.staticMethod());

⭐ 靜態方法的用例

  1. 實用函數:不需要物件狀態的方法。

  2. 工廠方法:建立具有特殊屬性的實例。

  3. 快取或固定配置:儲存所有實例的共享資料。

工廠方法範例:

class User {
    constructor(name, role) {
        this.name = name;
        this.role = role;
    }

    static createAdmin(name) {
        return new User(name, "admin");
    }
}

const admin = User.createAdmin("Alice");
console.log(admin.role); // Output: admin

⭐ 要點

  1. 靜態方法是在類別上定義的,而不是在實例上定義的。

  2. 使用類別名稱呼叫它們: ClassName.methodName()

  3. 它們可以被子類別繼承。

  4. 他們無法直接存取實例屬性或方法。

  5. 它們對於實用函數、工廠方法和管理類別級資料很有用。

  6. 您不能在實例上呼叫靜態方法,也不能在類別上呼叫實例方法。

▶️吸氣劑和吸氣劑

getter 和 setter 是分別允許您取得和設定物件值的函數

//getter setter
class human {
    constructor(name, age) {
        this._name = name;
    }
    get getName() {
        return this._name;
    }
    set setName(name) {
        this._name = name;
    }
}

const person = new human("", 0);
person.setName = "Raj";
person.setAge = 25;

console.log(person.getName);
console.log(person.getAge);

//Raj
//25

▶️instanceOf 運算符

檢查物件是否為類別、子類別或介面的實例

//getter setter
class human {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    get getName() {
        return this.name;
    }
    set setName(name) {
        this.name = name;
    }
    get getAge() {
        return this.age;
    }
    set setAge(age) {
        this.age = age;
    }
}

const person = new human("", 0);
person.setName = "Raj";
person.setAge = 25;

console.log(person.getName);
console.log(person.getAge);

const person1 = "Subham"

console.log( person instanceof human)//true
console.log( person1 instanceof human)//false

對於子類別它也傳回 true

//getter setter
class human {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    get getName() {
        return this.name;
    }
    set setName(name) {
        this.name = name;
    }
    get getAge() {
        return this.age;
    }
    set setAge(age) {
        this.age = age;
    }
}

class Coder extends human {
    constructor(name, age, language) {
        super(name, age);
        this.language = language;
    }
}

const person = new human("", 0);
const subham = new Coder("subham", 22, "java");
person.setName = "Raj";
person.setAge = 25;

console.log( person instanceof human)
console.log( subham instanceof human)

▶️封裝

封裝是一種限制對物件某些元件的直接存取的方法

class BankAccount {
    #balance; // Private field

    constructor(initialBalance) {
        this.#balance = initialBalance;
    }

    deposit(amount) {
        if (amount > 0) {
            this.#balance += amount;
        }
    }

    getBalance() {
        return this.#balance;
    }
}

const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
// console.log(account.#balance); // Syntax error: private field
//Encapsulation
const user = {
    firstName: "John",
    lastName: "Doe",
    age: 25,
    getAgeYear: function() {
        return new Date().getFullYear() - this.age;
    }
}
console.log(user.getAgeYear());

▶️ 多態性

多態性意味著“多種形式”,當我們有許多透過繼承相互關聯的類別時,就會發生多態性。

// Parent class
class Animal {
  makeSound() {
    console.log("The animal makes a sound");
  }
}

// Child classes
class Dog extends Animal {
  makeSound() {
    console.log("The dog barks");
  }
}

class Cat extends Animal {
  makeSound() {
    console.log("The cat meows");
  }
}

// Function to demonstrate polymorphism
function animalSound(animal) {
  animal.makeSound();
}

// Usage
const animal = new Animal();
const dog = new Dog();
const cat = new Cat();

animalSound(animal); // Output: The animal makes a sound
animalSound(dog); // Output: The dog barks
animalSound(cat); // Output: The cat meows

▶️ 抽象

抽像是隱藏複雜的實作細節並僅顯示物件的必要特徵的概念。

// Abstraction: Hiding complex implementation details and showing only the necessary features of an object.

// Abstract class
class Vehicle {
    constructor(brand) {
        this.brand = brand;
    }

    // Abstract method
    start() {
        throw new Error("Method 'start()' must be implemented.");
    }

    getBrand() {
        return this.brand;
    }
}

// Concrete class
class Car extends Vehicle {
    start() {
        return `${this.brand} car is starting...`;
    }
}

// Usage
const myCar = new Car("Toyota");
console.log(myCar.getBrand()); // Output: Toyota
console.log(myCar.start());    // Output: Toyota car is starting...

原文出處:https://dev.to/codexam/oops-in-js-ultimate-4j34


共有 0 則留言