前言
試著將對 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
- a 身上有沒有 sayHello
a.__proto__
有沒有 sayHello ,也就是Dog.prototype
有沒有 sayHello,以我們 的範例來說是有的,便會找到Dog.prototype.sayHello
,假設沒有便會再往上找a.__proto__.__proto__
有沒有 sayHello,那這個是甚麼呢?其實這個就是a.__proto__.__proto__ === Object.prototype // true
也許你會問,為甚麼是這個答 案,當我們印出 a 時就會知道為甚麼console.log(a) // Dog{ name:"david" }
這樣一串一串之間的關係,就被稱為 "原型鍊"
最後一個小插曲
那 Dog.__proto__
是甚麼呢? 答案是 Function.prototype
很合理,因為 Dog 本來就是一個 function,那好奇的你可能會想試試 Functiom
跟 Object
之間的原型鍊關係,這裡就先不講這個,大家可以試著玩玩看,因為有些複雜我自己吸收也還沒到能用文字敘述出來的程度。
總結
以上就是小弟對這次的主題的理解,希望有幫助到一些程式新手,如果這篇文章有幫助到你(妳),希望可以給我個愛心,給我鼓勵,使我更有寫技術文章的動力,如果有錯誤的地方,請各位前輩不吝指導,謝謝。
參考
Lidemy 課程內容:https://lidemy.com/
https://www.cnblogs.com/pssp/p/5216085.html