(Day 20) Object.create 建立多层继承

上回介绍了如何使用建构式来建立原型,接着今天介绍使用 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 核心篇 (六角学院)

<<:  【第5天】资料前处理-去除杂讯与灰阶

>>:  [Golang] Custom Type Declarations and Struct

[Day30] 初探视觉化

今天是最後一天,终於… 我选择最後能初探一下的,就是资料视觉化啦。 Kibana Visualize...

【Day 1】大纲 / 30 天的学习计画

身为一个普大的普通大学生, 实战经验少得可怜, 除了学过资工基本学科,就只会用 Python 写 L...

Day 23 : 插件篇 02 — 如何在 Obsidian 中自动汇整笔记?使用 Dataview 查询与呈现符合条件的笔记

一、介绍 这是 Obsidian 使用教学 — 插件篇的第 2 篇文章。 在 上一篇文章 中,我介绍...

白字黑字记录,足以降低有人要你当替罪羔羊

记录可以少走一些坑 因为主管、同事的推坑陷害,背上莫须有的罪名,让你的分红考绩化为乌有,那你一定要观...

【Day10】 声音转换概述 - 再次出发!

前言 在经过前面 9 天的准备之後,我们终於有些本钱可以涉足这个领域了,整理一下我们现在所掌握的 知...