前端开发,必知ES5、ES6的7种继承

雨点打透心脏的1/2处 2023-02-13 03:44 36阅读 0赞

众所周知,在ES6之前,前端是不存在类的语法糖,所以不能像其他语言一样用extends关键字就搞定继承关系,需要一些额外的方法来实现继承。下面就介绍一些常用的方法,红宝书已经概括的十分全面了,所以本文基本就是对红宝书继承篇章的笔记和梳理。
在这里插入图片描述
原型链继承

  1. function Parent() {
  2. this.name = 'arzh'
  3. }
  4. Parent.prototype.getName = function () {
  5. console.log(this.name)
  6. }
  7. function Child() {
  8. }
  9. //主要精髓所在
  10. Child.prototype = new Parent()
  11. Child.prototype.constructor = Child
  12. var arzhChild = new Child()
  13. arzhChild.getName() // 'arzh'

原型链继承缺点:

每个实例对引用类型属性的修改都会被其他的实例共享

  1. function Parent() {
  2. this.names = ['arzh','arzh1'];
  3. }
  4. function Child() {
  5. }
  6. //主要精髓所在
  7. Child.prototype = new Parent()
  8. Child.prototype.constructor = Child
  9. var arzhChild2 = new Child()
  10. arzhChild2.names.push('arzh2')
  11. console.log(arzhChild2.names) //[ 'arzh', 'arzh1', 'arzh2' ]
  12. var arzhChild3 = new Child()
  13. arzhChild3.names.push('arzh3')
  14. console.log(arzhChild3.names) //[ 'arzh', 'arzh1', 'arzh2', 'arzh3' ]

在创建Child实例的时候,无法向Parent传参。这样就会使Child实例没法自定义自己的属性(名字)

借用构造函数(经典继承)

  1. function Parent() {
  2. this.names = ['arzh','arzh1']
  3. }
  4. function Child() {
  5. Parent.call(this)
  6. }
  7. var arzhChild2 = new Child()
  8. arzhChild2.names.push('arzh2')
  9. console.log(arzhChild2.names) //[ 'arzh', 'arzh1', 'arzh2' ]
  10. var arzhChild3 = new Child()
  11. arzhChild3.names.push('arzh3')
  12. console.log(arzhChild3.names) //[ 'arzh', 'arzh1', 'arzh3' ]

优点:

解决了每个实例对引用类型属性的修改都会被其他的实例共享的问题
子类可以向父类传参

  1. function Parent(name) {
  2. this.name = name
  3. }
  4. function Child(name) {
  5. Parent.call(this, name)
  6. }
  7. var arzhChild = new Child('arzh');
  8. console.log(arzhChild.name); // arzh
  9. var arzhChild1 = new Child('arzh1');
  10. console.log(arzhChild1.name); // arzh1

缺点:

无法复用父类的公共函数
每次子类构造实例都得执行一次父类函数
组合式继承(原型链继承和借用构造函数合并)

  1. function Parent(name) {
  2. this.name = name
  3. this.body = ['foot','hand']
  4. }
  5. function Child(name, age) {
  6. Parent.call(this, name)
  7. this.age = age
  8. }
  9. Child.prototype = new Parent()
  10. Child.prototype.constructor = Child
  11. var arzhChild1 = new Child('arzh1', '18')
  12. arzhChild1.body.push('head1')
  13. console.log(arzhChild1.name,arzhChild1.age) //arzh1 18
  14. console.log(arzhChild1.body) //[ 'foot', 'hand', 'head1' ]
  15. var arzhChild2 = new Child('arzh2', '20')
  16. arzhChild2.body.push('head2')
  17. console.log(arzhChild2.name,arzhChild2.age) //arzh2 20
  18. console.log(arzhChild2.body) //[ 'foot', 'hand', 'head2' ]

优点:

解决了每个实例对引用类型属性的修改都会被其他的实例共享的问题
子类可以向父类传参
可实现父类方法复用
缺点:

需执行两次父类构造函数,第一次是Child.prototype = new Parent(),第二次是Parent.call(this, name)造成不必要的浪费
原型式继承
复制传入的对象到创建对象的原型上,从而实现继承

  1. function createObj(o) {
  2. function F(){}
  3. F.prototype = o;
  4. return new F();
  5. }
  6. var person = {
  7. name : 'arzh',
  8. body : ['foot','hand']
  9. }
  10. var person1 = createObj(person)
  11. var person2 = createObj(person)
  12. console.log(person1) //arzh
  13. person1.body.push('head')
  14. console.log(person2) //[ 'foot', 'hand', 'head' ]

缺点: 同原型链继承一样,每个实例对引用类型属性的修改都会被其他的实例共享

寄生式继承
我们可以使用Object.create来代替上述createObj的实现,原理基本上是一样的。寄生式继承其实就是在createObj的内部以某种形式来增强对象(这里的增强可以理解为添加对象的方法),最后返回增强之后的对象。

  1. function createEnhanceObj(o) {
  2. //代替原型式继承的createObj
  3. var clone = Object.create(o)
  4. clone.getName = function () {
  5. console.log('arzh')
  6. }
  7. return clone;
  8. }

通过createEnhanceObj就可以在创建对象的时候,把对象方法也通过此种方式继承。缺点: 同借用构造函数一样,无法复用父类函数,每次创建对象都会创建一遍方法

寄生组合式继承
不需要为了子类的原型而多new了一次父类的构造函数,如Child.prototype = new Parent() 只需要复制父类原型的一个副本给子类原型即可

  1. function inheritPrototype(Parent, Child){
  2. Child.prototype = Object.create(Parent.prototype) //创建父类原型的一个副本,把副本赋值给子类原型
  3. Child.prototype.constructor = Child;
  4. }
  5. function Parent(name) {
  6. this.name = name
  7. }
  8. Parent.prototype.getNmae = function () {
  9. console.log(this.name)
  10. }
  11. function Child(color) {
  12. Parent.call(this, 'arzh')
  13. this.color = color
  14. }
  15. inheritPrototype(Parent, Child)
  16. var arzhChild = new Child('red')
  17. console.log(arzhChild.name) // 'arzh'

优点: 不必为了指定子类型的原型而调用父类型的构造函数

ES6继承
ES6支持通过类来实现继承,方法比较简单,代码如下

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x
  4. this.y = y
  5. }
  6. toString() {
  7. return this.x + '' + this.y
  8. }
  9. }
  10. class ColorPoint extends Point {
  11. constructor(x, y, color) {
  12. super(x, y) //调用父类的constructor(x, y)
  13. this.color = color
  14. }
  15. toString() {
  16. return this.color + ' ' + super.toString() // 调用父类的toString()
  17. }
  18. }
  19. var colorPoint = new ColorPoint('1', '2', 'red')
  20. console.log(colorPoint.toString()) // red 12

点此链接:最后我自己是一名从事了多年开发的web前端老程序员,今年年初我花了一个月整理了一份最适合2020年学习的前端学习干货,想分享给每一位喜欢前端的小伙伴

发表评论

表情:
评论列表 (有 0 条评论,36人围观)

还没有评论,来说两句吧...

相关阅读