老生常谈:初探原型与继承

156 阅读2分钟

原型

几个知识点

  • 我们都知道js中引用类型(数组、函数、对象)都是对象,而且分别由ArrayFunctionObject构造函数创建,例如常见的字面量创建其实也可以用构造函数
const arr = []
const arr2 = new Array()

const fn = name => console.log(name)
const fn2 = new Function('name', 'console.log(name)')

const obj = {}
const obj2 = new Object()
  • 函数拥有prototype属性,而任意对象拥有__proto__属性,即:
    • 函数:prototype__proto__
    • 任意对象:__proto__

关系

所谓的原型链其实是指__proto__prototype的从属关系,且一个属性会从实例最开始寻找直到顶层为止(继承的表现之一),即下面图形版的红色线条路线。

代码示例为:

// Foo的父类构造函数
const SupperFoo = function (sex) {
  this.sex = sex
}
SupperFoo.prototype.sName = 'supper prototype'

// Foo构造函数
const Foo = function (name, age) {
  this.name = name
  this.age = age
}
Foo.prototype = Object.create(SupperFoo.prototype)
Foo.prototype.pName = 'foo prototype'

const foo = new Foo('pz', 25)

// 继承表现之一
console.log(foo.sName) // 'supper prototype'

图形版

)

文字版

  • 对象实例.__proto__ === 构造函数.prototype
  • 构造函数.prototype.__proto__ === 父构造函数.prototype(如果父构造函数又继承于其他函数,则关系类似,一直直到顶层构造函数)
  • 顶层构造函数.prototype.__proto__ === Object.prototype
  • Object.prototype.__proto__ === null

一层特殊的关系:Object.__proto__ === Function.prototype

继承

es5写法

主要是prototype和本体的处理

// Car类 - 父类
function Car() {}
// Audi - 子类
function Audi() {
  Car.call(this)
}
// 推荐,es6式继承方法
// 等同于 Object.setPrototypeOf(Audi.prototype, Car.prototype)
Audi.prototype = Object.create(Car.prototype)
Audi.prototype.constructor = Audi

// 不建议使用 Audi.prototype = new Car()
// 不建议使用 Audi.prototype = Car.prototype

es6写法

  • 继承时注意实现super
  • static为类方法
class Car {
  constructor(name, color) {
    this.name = name
    this.color = color
  }
  showName () {
    console.log(this.name)
  }
  static say () {
    console.log('I am car.')
  }
}

class Audi extends Car {
  constructor (name, color, price) {
    super(name, color)
    this.price = price
  }
  showPrice () {
    console.log(this.price)
  }
}

后续待解决

  • 字面量创建对象与构造函数创建对象的区别
  • new的具体代码实现
  • 继承在实际业务中的利用点
  • ...