专栏首页M不作声JavaScript实现继承

JavaScript实现继承

在面向对象编程中有一个很重要的特性,就是继承,通过继承可以减小大量冗余的代码。

JS也是可以面向对象编程的,在JS里也有多种继承方式。

class继承

class是ES6增加的关键字,他的本质还是函数。

使用class继承非常简单。子类使用extends关键字表明继承于哪个类,并在子类中调用super(),这相当于使用call()改变this的指向。

class继承代码如下:

class Person {
  constructor(value){
    this.value = value
  }
    
  getValue() {
    console.log(this.value)
  }
}

class person {
  constructor(value){
    super(value)
  }
}

let p = new person()
p instanceof person //true
p instanceof Person //true

原型链继承

function Name() {
  this.name = 'name'
}

function Age() {
  this.age = 'age'
}
Age.prototype = new Name() //Age的原型对象是Name的实例对象,将Age添加到原型链上
let age = new Age
console.log(age.name, age.age) //name age

原型链继承就是使用的它的概念对象._proto_ = 构造函数.prototype

构造函数继承

function Father(age) {
  this.name = ['zhao', 'qian']
  this.age = age
}
function Son(age) {
  Father.call(this, age)
}
let son = new Son(12)
console.log(son.age) // 12
console.log(son.name) // ["zhao", "qian"]
son.name.push('zhou') // 3
console.lgo(son.name) // ["zhao", "qian", "zhou"]

组合继承

组合继承是原型链继承+构造函数继承,原型链继承的属性,构造函数继承方法。原型链继承会出现一个问题:包含引用类型值的原型属性,会被所有实例共享。构造函数继承的问题是:没有原型,无法复用

组合继承代码如下:

function Father(age) {
  this.name = ['zhao', 'qian']
  this.age = age
}
Father.prototype.run = () => { return this.name + ' ' + this.age}

function Son(age) {
  Father.call(this, age)
}

Son.prototype = new Father()
let son = new Son(12)
console.log(son.run()) //zhao,qian 12

这种继承方式通过Father.call(this)继承父类的属性,通过new Father()继承父类的函数。优点在于构造函数可以传参,不会与父类共享属性,缺点是在继承父类函数的时候调用了父类的构造函数

寄生组合继承

组合继承的缺点是在继承时调用了父类的构造函数。寄生组合继承解决了两次调用的问题。

function Parent (name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
  
Parent.prototype.getName = () => { console.log(this.name) }
  
function Child (name, age) {
  Parent.call(this, name);
  this.age = age;
}
 
function prototype(Child,Parent){ //获得父类型原型上的方法
    let prototype = object(Parent.prototype) //创建父类型原型的一个副本,相当于prototype.__proto__ = Parent.prototype
    prototype.constructor = Child
    Child.prototype = prototype
}
 
prototype(Child,Parent) //必须执行这个函数,才能进行给子类型原型写方法,顺序调转的话子类型原型会被重写
Child.prototype.getName = () => { console.log(this.name) }

总结

  • 原型链继承来自父类原型对象的引用属性是所有子类共享的;创建子类实例时,无法向父类构造函数传参
  • 构造函数继承解决了上述问题,但无法实现函数的复用,方法在构造函数中定义,每次创建子类实例都会创建一个新方法,占用内存。
  • 组合继承解决了上述问题,使用原型继承继承父类的属性Parent.call(this),使用构造函数继承父类的方法new Parent()。但子类调用了两次父类构造函数,生成了两个父类实例。
  • 寄生组合继承解决了上述问题,但是使用复杂。
  • class是ES6的语法,使用extends指定继承的父类。

今天不学习,明天变垃圾。

欢迎关注公众号:前端大合集。

本文分享自微信公众号 - 大前端合集(fe-stack),作者:M不作声

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 反转单链表

    这结果简直拉胯,我们来做时间和空间复杂度分析,将链表遍历一遍拆掉入栈,然后再将栈遍历一遍出栈生成链表,时间复杂度大致为O(2n),而为了存储节点借用了一个栈的数...

    不作声
  • 628笔试题

    第一次输出[9,2,3] [9,2,3],第二次输出[4,5,6] [9,2,3]

    不作声
  • 用JS手动实现一个栈和队列

    栈是一个「线性」的数据结构。栈最重要的特征是「只允许从一端操作数据」。栈就像一叠书,或者盘子,每次只能从最上边拿,往最上边放。

    不作声
  • PHP中__set()实例用法和基础讲解

    PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用。 其中__set(),设置一个类的成员...

    砸漏
  • javascript 面向对象(多种创建对象的方式)

    创建对象 第一种:基于Object对象 var person = new Object(); person.name = 'My Name'; person.a...

    柴小智
  • 设计模式(3)[JS版]-JavaScript中的构造函数模式是什么?

    构造函数用于创建特定类型的对象一不仅声明了使用的对象,构造函数还可以接受参数以便第一次创建对象的时候设置对象的成员值。你可以自定义自己的构造函数,然后在里面声明...

    AlbertYang
  • C++构造函数互调纠正

    现在有这么一个问题,有一个带参数的构造函数,当默认构造去调这个带参数的构造,在Java中大家都明白,直接穿个this(xxx)就可以了,那就在C++中模仿一下,...

    公众号guangcity
  • 快速掌握this

    在Java语言中,当创建一个对象后,Java虚拟机就会为其分配一个指向该对象本身的指针,这个指针就是this。this只能用于在类的非静态方法或者构造方法中,在...

    田维常
  • 自定义泛型实例

    public class UserDefined { public static void main(String[] args) { ...

    MonroeCode
  • Java ConcurrentModificationException异常原因和解决方法

    小小明童鞋

扫码关注云+社区

领取腾讯云代金券