物件導向、原型鍊、this 淺淺談


Posted by david-christian on 2021-02-11

前言

試著將對 Javascript 物件導向、原型鍊這個經典題整理成文章,文章深度沒有非常的深,因為我自己也沒有研究的那麼透徹,所以整篇文章較利於程式新手先概略式的理解這些內容。

甚麼是實例?

範例使用的是 ES6 的寫法,因為我覺得這個寫法比較容易明白"實例" 這個名詞,簡單理解就是先透過 class 創建出一個類似設計圖的概念,並且透過 new 來創建出該設計圖的實例。

看到這裡也許你會先對 "實例" 兩字感到不理解,但我們先理解 class 的中文字義
class 中文字義又叫 "類別",而實例其實就是一個類別的真實對象,還不夠清楚嗎?
我們都是"人類",但是"你"和"我"都是"人類"的實例。

看到下面的例子可能會更方便理解,有一個類別 HumanRace (人類)
變數a 跟 變數b 分別都是這個類別的實例。

class HumanRace { // class 的名稱首字一定要大寫
    // constructor 又叫建構子
    constructor(name) {
        this.apple = name
    }
    sayHello() {
        console.log(this.apple)
    }
}

const a = new HumanRace("david")
const b = new HumanRace("Tina")
a.sayHello() // david
b.sayHello() // Tina

你也可以想像 class HumanRace 就像一個設計圖,它去定義一個設計圖有怎樣的行為、有甚麼方法可以呼叫,透過創建出這個設計圖的實例,就可以操作設計圖當初設計好的功能。

constructor 又名建構子,在創建出實例的時候執行,可以接收到一開始 new 的參數 const a = new HumanRace("david"),所以 constructor 的參數 name 就會是"david" 適合做一些初始化的動作。

this 這邊先淺談此情況下的 this 就好,實際上 this 的應用會更多,這裡的 this 它的指向就會是 a 這個對象,所以當我們用 this.apple 的時候,實際上就是給對象a添加屬性apple 然後值是 name 的值,然後透過類似像操作物件的方式,就可以讓實例使用,基本上這就稱為是物件導向。
還有一個部份需要知道的是,console.log(a.sayHello === b.sayHello) // true
兩個 function 是一樣的,兩個實例調用的是同一個函數。

透過物件導向 ES5 的寫法,來認識原型鍊

在 ES5 裡面,可以透過 new 來讓一個 function 變成像是 ES6 的 constructor 一樣
在 ES6 裡,我們 new 出一個對象的時候,傳進去的參數可以被 constructor 調用

class Dog { 
    constructor(name) {
        this.name = name
    }
    sayHello() {
        console.log(this.name)
    }
}

const a = new Dog("david")
a.sayHello() // david

如果不用 ES6 的 class 語法,透過 new 也能讓 a 變成 Dog 的實例
並且有類似像 constructor 的操作方法

function Dog(name) {
    this.name = name
}

const a = new Dog("david")
console.log(a.name) // david

而如果我們要達到跟 ES6 class 語法一樣的效果,則要開始使用到所謂的 "原型鍊"

function Dog(name) {
    this.name = name
}
Dog.prototype.sayHello = function() {
    console.log(this.name)
}

const a = new Dog("david")
a.sayHello() // david

甚麼是原型鍊?

首先跟原型鍊較為相關的有兩個 javascript 的內部屬性,即是prototype__proto__
可以先思考一個問題,以上面為例,a.sayHello 是以甚麼樣的方式來跟Dog.prototype.sayHello 有連結的呢?答案其實就是這樣
console.log(a.__proto__ === Dog.prototype) // true這也是 new 幫我們設定好的事情。

當我們下指令 a.sayHello() 的時候,javascript 會先依著以下順序,也就是按著層級順序,尋找 sayHello 這個 function

  1. a 身上有沒有 sayHello
  2. a.__proto__ 有沒有 sayHello ,也就是 Dog.prototype 有沒有 sayHello,以我們 的範例來說是有的,便會找到Dog.prototype.sayHello,假設沒有便會再往上找
  3. a.__proto__.__proto__ 有沒有 sayHello,那這個是甚麼呢?其實這個就是 a.__proto__.__proto__ === Object.prototype // true 也許你會問,為甚麼是這個答 案,當我們印出 a 時就會知道為甚麼 console.log(a) // Dog{ name:"david" }這樣一串一串之間的關係,就被稱為 "原型鍊"

最後一個小插曲

Dog.__proto__ 是甚麼呢? 答案是 Function.prototype很合理,因為 Dog 本來就是一個 function,那好奇的你可能會想試試 FunctiomObject 之間的原型鍊關係,這裡就先不講這個,大家可以試著玩玩看,因為有些複雜我自己吸收也還沒到能用文字敘述出來的程度。

總結

以上就是小弟對這次的主題的理解,希望有幫助到一些程式新手,如果這篇文章有幫助到你(妳),希望可以給我個愛心,給我鼓勵,使我更有寫技術文章的動力,如果有錯誤的地方,請各位前輩不吝指導,謝謝。

參考

Lidemy 課程內容:https://lidemy.com/
https://www.cnblogs.com/pssp/p/5216085.html


#物件導向 #原型鍊 #this







Related Posts

DAY 02 : 演算法基本概念

DAY 02 : 演算法基本概念

智能合約(一) - 什麼是智能合約?

智能合約(一) - 什麼是智能合約?

--save-dev 與 --save 的不同

--save-dev 與 --save 的不同


Comments