关于原型

103 阅读2分钟

作为 JavaScript 的一大特色,原型给很多初入前端的人带来了相当大的困扰(对,我说的就是我自己)。

JavaScript的数据类型

众所周知,JavaScript 中有 8 种数据类型

  • 原始类型
    • undefined
    • boolean
    • number
    • string
    • null
    • bigint
    • symbol
  • object

更详细可查看 MDN

本次所说的原型,只跟 Object 有关。暂时不管其他几种原始类型了。

显式原型与隐式原型

  • 显式原型 prototype
  • 隐式原型 __proto__

任意对象都有隐式原型,只有函数才有显式原型

显式原型

创建函数的时候,这个函数会自动带有 prototype 属性。这个属性值类型是一个也是一个对象,称之为原型对象。该对象中有一个 constructor 属性,属性值指向函数本身。

function fn () {}

console.log(fn.prototype.constructor === fn); // true

隐式原型

JavaScript 种任意对象都有一个隐式原型。在浏览器中,可通过 __proto__ 访问其隐式原型对象。对象的隐式原型总是指向其构造函数的原型对象

function fn () {}

console.log(fn.__proto__ === Function.prototype); // true

因为 fn 是 Function 的实例,也就是说其构造函数是 Function。

一个例外

Object 原型对象的隐式原型为 null。这是个规定,不解释。就好比,不能证明公理一样,这个规定是 JavaScript 的公理。

Object.prototype.__proto__ === null; // true

原型链

了解显式原型和隐式原型后,就可以很明白的解释清楚原型链了。原型链,这是一条链,体现在哪里?就体现在对象的隐式原型总是指向其构造函数的原型对象这句话上。

class Animal {}

class Dog extends Animal {}

class ChineseDog extends Dog {}

const chineseDog = new ChineseDog()

console.log(chineseDog.toString())

先想一下,关于 chineseDog 以及各个 function 的原型之间的联系怎样

graph TD
chineseDog --> chineseDog.__proto__
chineseDog --> ChineseDog.prototype
 
chineseDog.__proto__ --> ChineseDog.prototype.__proto__ 
chineseDog.__proto__ --> Dog.prototype 

ChineseDog.prototype.__proto__ --> Dog.prototype.__proto__
ChineseDog.prototype.__proto__ --> Animal.prototype

Dog.prototype.__proto__ --> Animal.prototype.__proto__
Dog.prototype.__proto__ --> Object.prototype


Animal.prototype.__proto__ --> Object.prototype.__proto__ --> null


看到没有,这就是原型链。上图中,所有处于平级的,都是等价的。例如 chinedeDog.__proto__ === Chinese.prototype

当访问一个 chineseDog 的 toString 时,就会顺着 __proto__ 这条链找下去,如果一直到最后还没找到,就会返回 null 。其实在本例中,最终会在 Object.prototype 也就是 Animal.prototype.__proto__ 上找到 toString 方法

一些代码

function Person () {}
var p = new Person();

Person.__proto__ === Function.prototype // true。因为 Person是function,是Function 的实例
Object.__proto__ === Function.prototype // true。因为 Object也是function,也是Function 的实例
Function.__proto__ === Function.prototype // true 因为 Function也是function,也是Function 的实例

最后,放一张神图~

image.png