前言

背景

JavaScript 的继承和 Java/C 等语言有很大的不同,关键就在于这个原型链,而我做了这么多年的 JavaScript 也一直没有彻底弄清楚。尤其是到了 Object.prototypeFunction.prototype 的层级就更云里雾里了,所以想这次一次弄清楚。

原型链

先看一张经典的描述原型链的图。

javascript-prototype

prototype 是所有函数都具有的属性,也被成为原型对象。在将该函数作为构造函数创建一个实例时,实例的 [[prototype]] 属性和该函数的 prototype 属性指向同一个对象。

function Person (name) {
  this.name = name
}

Person.prototype.greet = function () {
  console.log('Hello, I\'m fat Tony')
}

const fatTony = new Person('Fat Tony')

fatTony.greet() // Hello, I'm fat Tony

console.assert(Object.getPrototypeOf(fatTony) === Person.prototype) // 实例的 [[prototype]] 属性指向构造函数的 prototype 属性
console.assert(Object.getPrototypeOf(Person.prototype) === Object.prototype) // 构造函数的原型对象本身也有 [[prototype]] 属性
console.assert(Object.getPrototypeOf(Object.prototype) === null) // 最终的原型对象是 null

console.assert(Object.getPrototypeOf(Function.prototype) === Object.prototype) // 原型对象自己也是对象,最后指向了 Object.prototype
console.assert(Object.getPrototypeOf(Object) === Function.prototype) // Object 本身是函数,因此它的原型对象指向 Function.prototype 并不令人奇怪
console.assert(Object.getPrototypeOf(Function) === Function.prototype) // 这个需要注意一下,Function 函数的 [[prototype]] 属性,指向的是它自己的原型对象
console.assert(Object.getPrototypeOf(Person) === Function.prototype) // 普通函数的 [[prototype]] 属性自然指向的是 Function.prototype 了

console.assert(Person === Person.prototype.constructor)
console.assert(Object === Object.prototype.constructor)

多种继承方法

  • 使用语法结构创建的对象
  • 使用构造器创建的对象
  • 使用 Object.create 创建的对象
  • 使用 class 关键字创建的对象

详细用法可以参见此文章

instanceof

instanceof 运算符用来检测构造函数的 prototype 属性是否存在于某个实例对象的原型链上。

参考资料