iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
自我挑戰組

JavaScript 奇奇怪怪的核心觀念系列 第 20

(Day 20) Object.create 建立多層繼承

  • 分享至 

  • xImage
  •  

上回介紹了如何使用建構式來建立原型,接著今天介紹使用 Object.create() 建立多層原型,先前在 T Shirt 例子有提到 , T Shirt 的原型是衣服,而衣服原型,仍然能有原型,這種多層原型就會使用 Object.create() 這個方法。

什麼是 Object.create()

Object.create() 這個功能簡單來說就是,建立一個新的原型物件,而這個原型物件是沒有實體的,這邊使用範例來觀察

const Ryder = {
	name:'Ryder'
}
const student = Object.create(Ryder)
console.log(student) //{}
student.name // Ryder

雖然 student 實體仍是空物件,但我們使用 student.name 可以看到他會回傳 Ryder

這是因為 Object.create() 的功能,讓 student 的原型繼承 Ryder 的內容 ,可以點開 student 回傳的空物件,看看他 [[Prototype]] 的結構:

這樣便清楚 Object.create() 的功能其實就是能夠讓參數中的內容,成為目標的原型。

透過 Object.create() 建立多層原型

這邊複製之前的 TShirt 程式碼

function TShirt(color,material,size){
	this.color = color
	this.material = material
	this.size = size
}

TShirt.prototype.clothe = function() {
  console.log(`穿上 ${this.color} T Shit`);
}

const BlackTShit = new TShirt('black','棉','L')

目前是的原型鍊是

BlackTShit (子層) ⇒ TShirt (父層)

預期在 TShirt 上一層在新增一層 apparel 原型,也就是讓原型鍊變成

BlackTShit ⇒ TShirt ⇒ apparel (服飾)

接下來就是新增 apparel 原型,並使用剛剛介紹的 Object.create() , 讓 apparel 成為 TShirt 的原型,以下是範例:

// 新的一層原型
function apparel(type){
	this.type = type || 'T Shirt'
}

// 為新原型新增方法
apparel.prototype.mirror = function(){
 console.log(`我穿著 ${this.color} 的 ${this.type} `)
}

function TShirt(color,material,size){
	this.color = color
	this.material = material
	this.size = size
}

// 使用 Object.create 讓 TShirt 原型繼承 apparel 原型
TShirt.prototype = Object.create(apparel.prototype)

TShirt.prototype.clothe = function() {
  console.log(`穿上 ${this.color} T Shit`);
}
const BlackTShit = new TShirt('black','棉','L')

在這段範例中要特別注意的是這一段:

TShirt.prototype = Object.create(apparel.prototype)

這邊是讓 TShirt 這個函式建構式的原型,繼承了 apparel 函式就建構式的原型。

多層繼承中的眉眉角角

在完成上面使用 Object.create() 串連原型後,接著試者使用 mirror() 以及 clothe() 方法。

BlackTShit.clothe() //穿上 black T Shit
BlackTShit.mirror() //我穿著 black 的 undefined

可以發現在 apparel 這一層原型新增的方法雖然成功了, mirror() 方法中的 type 屬性卻無法正確顯示,這是因為使用 Object.create()TShirt 繼承了 apparel 的原型,但卻沒有繼承 apparel 的『建構函式』。
這時候需要在 TShirt 建構函式中使用 call() 方法,來讓 TShirt 中的 this 綁定到 apparel 上,而這段其實就是將兩個 建構函式 串接起來,並在傳入 'T Shirt' 字串當作 appareltype 參數。

function apparel(type){
  this.type = type || '帽 T'
}
apparel.prototype.mirror = function(){
  console.log(`我穿著 ${this.color} 的 ${this.type} `)
}

function TShirt(color,material,size){
  apparel.call(this, 'T Shirt')
  this.color = color
  this.material = material
  this.size = size
}
TShirt.prototype = Object.create(apparel.prototype)
TShirt.prototype.constructor = TShirt
TShirt.prototype.clothe = function() {
  console.log(`穿上 ${this.color} T Shit`);
}

const BlackTShit = new TShirt('black','棉','L')
BlackTShit.mirror()
BlackTShit.clothe()

這樣在 console 打上 BlackTShit 便會看到,來自 TShirt 原型 、apparel 原型上的完整屬性以及內容了。

最後這邊看起來程式碼已經相當的完整了,但是如果要讓原型鍊完整的話,其實還必須在 Object.create() 底下加上 TShirt.prototype.constructor = TShirt ,這是因為在 Object.create() 設定時就會將原本 TShirt 原型中的內容在加回來。

function apparel(type){
	this.type = type || '帽 T'
}
// 為新原型新增方法
apparel.prototype.mirror = function(){
 console.log(`我穿著 ${this.color} 的 ${this.type} `)
}

function TShirt(color,material,size){
	apparel.call(this, 'T Shirt')
  this.color = color
	this.material = material
	this.size = size
}

// 透過 Object.create() 為 TShirt  
TShirt.prototype = Object.create(apparel.prototype)
TShirt.prototype.constructor = TShirt

TShirt.prototype.clothe = function() {
  console.log(`穿上 ${this.color} T Shit`);
}
const BlackTShit = new TShirt('black','棉','L')
BlackTShit.mirror()
BlackTShit.clothe()

這樣就是完整的讓原型繼承原型的方法了。

參考文獻

  • JavaScript 核心篇 (六角學院)

上一篇
(Day 19) 原型與建構式
下一篇
(Day 21) ES6 class 語法糖
系列文
JavaScript 奇奇怪怪的核心觀念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言