ES5实现继承

95 阅读3分钟

前言

继承是面向对象技术中的一个概念,可以使得子类具有父类的属性和方法,同时可以重写父类的属性和方法。在JavaScript中,实现面向对象编程的方式与传统面向对象语言不同,主要体现在传统面向对象语言基于类,而JavaAcript基于原型和原型链机制来实现。因此,本篇主要讲解在JavaScript中,如何利用ES5的原型和原型链机制来实现继承这一特性。

正文

ES5中主要有四种实现方式,分别为原型链继承、借用构造函数继承、组合式继承、寄生式组合继承。这几种方式的发展顺序可以简单理解为循序渐进发展的,一般后一种都是补足了前一种的问题(可以对比下一种的优点和上一种的缺点来看);显而易见,寄生式组合继承是最这几种最优秀的一种继承方式。

第一种 原型链继承

1.1 是什么?

  • 父类创建一个实例作为子类的原型对象。(如:Children.prototype = new Parent())

1.2 查找顺序

  • 子类实例--->父类实例--->父类原型对象

1.3 优缺点

  • 优点:可以访问父类原型对象上的属性。
  • 缺点:
    1. 无法向父类传参(super()功能)
    2. 若new Parent()是引用类型,则修改时会影响所有的child实例。

第二种 借用构造函数继承

2.1 是什么?

  • 在子类构造函数中执行父类函数,并为其绑定子类的this,理解代码如下:
function Children() {
    Parent.apply(this, arguments)
}

2.2 查找顺序

  • 子类实例--->子类原型对象--->父类构造函数

2.3 优缺点

  • 优点:
    1. 避免实例之间共享一个原型实例
    2. 可以向父类构造方法传参
  • 缺点:
    1. 获取不到父类原型对象上的属性和方法。(这个第一种方式(即原型链继承)可以获取)

过渡语:借用构造函数继承的缺点刚好原型链继承可以弥补,于是将他们两个组合使用就有了第三种方式,即组合式继承。

第三种 组合式继承(原型链+借用构造函数)

3.1 是什么?

  • 将原型链式继承和借用构造函数继承组合使用。

3.2 优缺点

  • 优点: 集合了上述两种方式的优点。
  • 缺点:
    1. 每当创建子类时(const child1 = new Children()),原型链式继承(Children.prototype === new Parent())会执行一次Parent构造函数;Parent.apply(this, arguments)也会执行一次Parent构造函数。也就是说,会执行两次Parent构造函数。
    2. 原型链上会存在两份相同的属性和方法,不优雅。

第四种 寄生式组合继承(原型链+寄生式函数+构造函数继承)

3.1 是什么?

  • 先来了解下Object.create(),以一个现有对象作为原型,创建一个新对象。
    1. 参数:它接收两个参数(proto, propertiesObject)其中第一个参数必选,为现有对象(并作为原型对象),第二个参数可选,是为新创建的对象添加具有对应属性名称的属性描述符。
    2. 返回值:返回根据指定的原型对象和属性创建的新对象。(这个对象可以通过.的方式来修改原型对象的属性和方法)

3.2 优缺点

  • 优点: 将指向父类实例改为指向父类原型,进而减去一次构造函数执行。也就是:Children.prototype = Object.create(Parent.prototype),此处父类和子类并不共享同一个原型对象。

3.3 核心代码

    Children.prototype = Object.create(Parent.prototype)
    Children.prototype.construct = Children

综上,Es5中实现继承主要通过以上方式,其中寄生式组合继承最好,发展顺序如图。

image.png