jeremygo

jeremygo

我是把下一颗珍珠串在绳子上的人

[Translation] JavaScript - Inheritance, Delegation Patterns, and Object Linking

Original Article: JavaScript — Inheritance, delegation patterns and Object linking

Author: NC Patro

Learn about inheritance, delegation patterns, and objects linked to other objects in JavaScript (prototype inheritance).

什麼是繼承#

在大多數基於類別的物件導向語言中,繼承是一種機制,讓一個物件可以獲得另一個物件的所有屬性和方法。儘管在 ES2015 中提出了 class 關鍵字,但 JavaScript 並不是一門基於類別的語言,它只是一種語法糖,本質上仍然是基於原型鏈的方式。

經典繼承與原型繼承#

繼承圖

經典繼承(非 JavaScript)#

  • Vehicle 是父類別,v1v2Vehicle 的實例。
  • CarVehicle 的子類別,而 c1c2Car 的實例。
  • 當我們繼承類別時,經典繼承會將父類別的行為複製到子類別中,然後父子類別就成為獨立的實體。
  • 這就像是汽車是用工具和汽車圖紙製造出來的,但製造完成後它們是獨立的個體,因為它們只是複製,所以它們之間沒有關聯,這就是所有箭頭向下(屬性和行為向下傳遞)的原因。

原型繼承(行為委派模式)#

  • v1v2 關聯到 Vehicle.prototype,因為它們是通過 new 創建的。
  • 同樣地,c1c2 關聯到 Car.prototype,而 Car.prototype 關聯到 Vehicle.prototype
  • JavaScript 中,當我們創建一個物件時,它不是複製屬性或行為,而是創建一個連結。在繼承類別時也會創建類似的連結。
  • 與經典的非 JavaScript 繼承相比,所有連結指向相反的方向,因為它是行為委派連結。這些連結稱為原型鏈。
  • 這種模式被稱為行為委派模式,通常稱為 JavaScript 中的原型繼承

您可以通過閱讀這篇文章 JavaScript - 原型 來深入了解原型鏈

原型繼承的例子#

  • 使用 Object.create() 實現經典繼承。
  • 在下面的程式碼片段中,Car.prototypeVehicle.prototype 通過 Object.create() 函數相連。
// Vehicle - 超類別
function Vehicle (name) {
    this.name = name;
}
// 超類別的方法
Vehicle.prototype.start = function () {
    return "engine of " + this.name + " starting...";
}

// Car - 子類別
function Car (name) {
    Vehicle.call(this, name); // 調用超類別的建構函數
}
// 子類別擴展超類別
Car.prototype = Object.create(Vehicle.prototype);
// 子類別的方法
Car.prototype.run = function () {
    console.log("Hello " + this.start());
}

// 子類別的實例
var c1 = new Car("Fiesta");
var c2 = new Car("Baleno");

// 存取內部存取超類別方法的子類別方法
c1.run();   // "Hello engine of Fiesta starting..."
c2.run();   // "Hello engine of Baleno starting..."
  • 在上述程式碼中,由於下面的原型鏈,物件 c1 可以存取 run() 方法和 start() 方法。如下圖所示,我們可以看到 c1 沒有這樣的方法,但它有向上的連結。
  • 上面程式碼中的 this 只是每個方法當前的執行上下文,即 c1c2

您可以瀏覽這篇文章 JavaScript - 關於 this 和 new 的所有內容 來詳細了解this關鍵字。

上述程式碼的圖解表示:

JavaScript 繼承圖

與其他物件關聯的物件#

  • 現在我們將簡化先前的繼承示例程式碼,只關注物件之間的連結。
  • 因此,我們將嘗試移除 .prototypeconstructornew 關鍵字,只考慮物件。
  • 我們將使用 Object.create() 函數來創建函數之間的所有連結。

以下是先前示例程式碼的簡化版:

// 包含初始化方法的基礎物件
var Vehicle = {
    init: function (name) {
        this.name = name;
    },
    start: function () {
        return "engine of " + this.name + " starting...";
    }
}

// 在子物件和基礎物件之間創建的委派連結
var Car = Object.create(Vehicle);

// 子物件的方法
Car.run = function () {
    console.log("Hello " + this.start());
};

// 具有委派連結的實例物件指向子物件
var c1 = Object.create(Car);
c1.init('Fiesta');

var c2 = Object.create(Car);
c2.init('Baleno');

c1.run();   // "Hello engine of Fiesta starting..."
c2.run();   // "Hello engine of Baleno starting..."

上述程式碼的圖解展示:

物件連結

  • 現在我們可以看到,我們如何消除了 new,所有 .prototype,建構函數和呼叫方法的複雜性,並且仍然實現了相同的結果。
  • 唯一重要的是 c1 連結到一個物件,然後再連結到另一個物件,依此類推。
  • 這也被稱為物件委派模式。

總結#

在程式碼中使用原型繼承和原型鏈之前,了解它們是很重要的,以避免複雜性。

參考資料:You Don't Know JS 系列書籍

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。