前端三十|15. [JS] 什麼是原型鏈?
今天是鐵人賽的第十五天,旅程進行到了一半,而本系列文 JavaScript 的部分也即將告一段落。經過了連續三天型別相關的內容,今天也將接續下去,跟大家聊聊許多開發者時常搞不清楚的「物件原型」及「原型鏈」。
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您前往購買支持!
物件原型
相信大家多少都有用過 map
將陣列內容依序處理的經驗吧?例如:
let arr = [0, 1, 2]
let doubleArr = arr.map(c => c * 2)
console.log(doubleArr) // 0, 2, 4
不知道你有沒有曾好奇過,像這邊的變數 arr
,本身並沒有設定 map
屬性,那為什麼可以使用 map
這個函式呢?
我們將它印出來看看:
console.log(arr)
// 0: 0
// 1: 1
// 2: 2
// length: 3
// __proto__: Array(0)
出現了名為 __proto__
的物件,我們可以再將其展開,便會看到所有 Array 物件可以使用的函式;當然,我們也可以在其中找到 map
函式,而這也正是我們範例中呼叫 arr.map
的那個函式:
console.log(arr.map === arr.__proto__.map) // true
這邊出現的 __proto__
物件,也就是所謂的 原型物件(Prototype) 。
不同於 Java、C# 等 基於類別(Class) 的物件導向程式語言,藉由透過定義 Class、建立實例(instance)、指定繼承等方式來傳遞屬性及方法;Javascript 則是個 基於原型(Prototype)的物件導向程式語言 ,透過預先建立出的原型物件,每當新物件建立時,便指定物件的原型要參照到哪個原型物件。
而當開發者呼叫物件的屬性或方法時,若物件本身沒有這項屬性/方法,JavaScript 會自動尋找它原型中的方法,這也就是為什麼我們可以直接呼叫 arr.map
而不會出錯的原因了。
原型鏈
眼尖的讀者可能已經發現了,在前述的例子中,__proto__
物件中仍然有 __proto__
屬性:
console.log(arr.__proto__) // Array 的…