6. Prototypal inheritance 的运作原理

(这篇会延续Constructor Function的内容,来解释 Prototype 和 Prototypal inheritance。)

(想看结论可以看粗体跟移到最下面。)


4. 关於 Constructor Function 解释建构子函式的文章时,有提到把属性(properties)和方法(methods)都丢进建构子,这种建立物件的方式会占用到大量的记忆体。

我们可以先看看这个例子:

function Person(name, age, country){ 

    this.name = name,
    this.age = age,
    this.country = country,

    this.sayHi = function(){
    console.log(this.name + " says Hi.");  
    }
}

let Tina = new Person("Tina", 22, "Taiwanese");  
let Winnie = new Person("Winnie", 108, "Japanese");  

console.log(Tina.sayHi === Winnie.sayHi); // output: false

Tina.sayHiWinnie.sayHi的比较结果是不相等,要怎麽解释这个结果呢?

也就是说,即使他们定义的method一模一样,也会被当成不同的物件 → 指向不同的记忆体位置
那麽, 假设今天要制造一百个物件,就会制造一百个sayHi() → 占用一百个记忆体位置

这时侯我们可以利用prototype:

function Person(name, age, height){
    this.name = name,
    this.age = age,
  this.country = country
}

Person.prototype.sayHi = function() {  // 在Person的prototype属性定义sayHi()
    console.log(this.name + " says Hi");
}

let Tina = new Person("Tina", 22, "Taiwanese");  
let Winnie = new Person("Winnie", 108, "Japanese");  

console.log(Tina.sayHi === Winnie.sayHi); // output: true

从这里可以知道,Tina.sayHiWinnie.sayHi两个函式严格相等(指向同样的记忆体位置),这样就可以解决占用记忆体的灾难。

那接下来要来了解,为什麽加入prototype可以解决这个问题?

所以我们要来认识JS的继承(inheritance)和原型链(Prototype chain):

prototypal inheritance 原型继承


  • 在JS里,所有的物件都有一个隐藏属性Prototype(原型),而prototype本身也是一个object(物件)。
  • prototype可能为null,或参考至其他物件。

In JavaScript, objects have a special hidden property [[Prototype]] (as named in the specification), that is either null or references another object. That object is called “a prototype”:

当我们需要读取一个物件的属性,却找不到时,JS会自动从从该物件的prototype查找。

在程序语言中,这个行为被称作 「原型继承」。 (← 全文重点

When we read a property from object, and it’s missing, JavaScript automatically takes it from the prototype. In programming, this is called “prototypal inheritance”.

从我们刚刚执行的例子,我们可以执行console.log(Tina);来了解他们的阶层关系:
https://ithelp.ithome.com.tw/upload/images/20210907/201294762znVkaYpjJ.png

  1. 物件Tina本身是建构子Person创造出来的实例(instance)。
  2. 最下方有个名为[[prototype]]的属性,展开可以看到建构子为Person()
  3. 再展开,最下方还是有个[[prototype]]属性,可以再看到建构子为Object()

由此可知,他们的继承(查找)机制是这样子:

Tina ---> Person.prototype(红色框) ---> Object.prototype(绿色框) ---> Null

(JS 使用 constructor function 来定义物件的属性与方法,而产生出的新物件被称为实例(Instance)。)


最後补充一下MDN的定义:

讲到继承,JavaScript 就只有一个建构子:物件。
每个物件都有一个连着其他原型(prototype)的私有属性(private property)物件。 原型物件也有着自己的原型,於是原型物件就这样链结,直到撞见 null 为止:null 在定义里没有原型、也是原型链(prototype chain)的最後一个链结。
引用自 继承与原型链 - JavaScript | MDN

做个结论:

→ 每个JS里的物件(object),都继承(inheritance)自该物件的原型(Prototype),并保留其属性和方法。

→ 使用建构子函式产生实例以後,这些被产生的物件之间的连结被称为原型链(Prototype chain)。

→ 当我们需要读取一个物件的属性,却找不到时,JS会自动从从该物件的prototype查找,也就是原型继承(prototypal inheritance)。

参考资料:

【如内文有误还请不吝指教>< 谢谢阅览至此的各位:D】

-----正文结束-----


<<:  第二天:什麽是 CI/CD?

>>:  Advanced CRM Study

予焦啦!准备工具链

本节是以 Golang 上游 1a708bcf1d17171056a42ec1597ca8848c...

JavaScript学习日记 : Day28 - console实用技巧

开发过程中常常会需要使用console.log()来检视输出是否正确,所以能够妥善运用各种conso...

【图解演算法教学】还在用古老的二元搜寻法?是时候跟上「Hash Search」的车尾灯了!

Youtube连结:https://bit.ly/2Uv2sBf 在我们还没学资料结构前,通常都用...

day16_Windows Arm 的游戏之旅

你最万能的游戏机 Windows PC windows 为市占率最高的电脑作业,他满足了人们音乐, ...

Hook 概观( Day15 )

如果想快速使用 Hook ,其实就参考 Hook 概观分的五个面向,包含一定会用也最常用的 Stat...