JS继承的几种方式

379 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

对继承一直迷迷茫茫,抽个下午出来总结一下

继承的几种方式

graph LR
A[继承]-->B-->D-->G
A-->C-->D
A-->E-->F-->G
B[原型链式继承]
C[借用构造函数]
D[组合式继承]
E[原型式继承]
F[寄生式继承]
G[组合寄生式继承]

原型链继承

  1. 要继承的函数
  2. 给父亲的原型一个方法
  3. 一个子函数
  4. 子函数的prototype = new父函数(获得父函数的实例)
  5. (如果需要可以给子函数的原型添加其他方法)
  6. (new 子函数,获得实例)
缺点

多个实例对引用类型的操作会被篡改。

实现
 function father(){
     this.name = "father"
 }
 father.prototype.say = function(){
     return this.name
 }
 function son(){
     this.childName = "Child"
 }
 ​
 son.prototype = new father()
 let son1 = new son()
 console.log(son1.say())

借用构造函数继承

  1. 要继承的父函数
  2. 子函数:调用父函数,使用call改变this指向
  3. (new 子函数,获得实例)
缺点

只能继承父类的实例属性和方法,不能继承原型属性和方法,无法实现复用,每个子类都有父类实力函数的副本,影响性能

实现
 function father(){
     this.name = "father"
 }
 function son(){
     father.call(this)
 }
 ​
 let son1 = new son()

组合继承

用原型链方法实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的集成。

  1. 需要继承的父函数
  2. 向父函数的原型上添加个方法
  3. 子函数,在子函数内部调用父函数,使用call改变this指向,继承属性,子函数可以添加新属性
  4. 子函数的原型=父函数的实例
  5. 子函数原型里的构造函数=子函数(在上一步 子函数原型的构造函数指向了父函数,指回来,因为在默认情况下,一个函数对象的原型的contructor属性指向这个函数对象, )
  6. (如果喜欢可以给子函数的原型增加一些方法)
  7. (new子函数 获得实例)
缺点

在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法

实现
 function father(name){
     this.name = name
 }
 father.prototype.say=function(){
     return this.name
 }
 function son(name,age){
     father.call(this,name)
     this.age=age
 }
 son.prototype = new father()
 son.prototype.constuctor = son

原型式继承

利用空对象作为中介,将某个对象直接赋值给空对象的原型

  1. 一个需要继承的对象
  2. let 新对象 = Object.create(旧对象)
实现
 let person = {
     name:"haha",
     family:['papa','mama']
 }
 ​
 let me = Object.create(person)
手写object.create()
 function mycreate(){
     funciton f(){}
     f.prototype = obj
     return new f()
 }
缺点

无法传递参数;原型链继承多个实例的引用类型属性指向相同,存在篡改的可能

寄生式继承

在原型式继承的基础上,增强对象,为构造函数新增属性和方法

  1. 一个需要继承的对象

  2. 手写一个实现寄生式继承的函数f

    1. 传入obj,let 新对象 = object.create(obj)
    2. 给新对象增加方法(这里大大增强了)
    3. 返回新对象
  3. let 新对象 = f(旧对象)

缺点

同原型式继承

实现
 let person = {
     name:"haha",
     family:['papa','mama']
 }
 ​
 function giveMeInheritance(obj){
     let newObj = Object.create(obj)
     newObj.function1 = function(){
         return "function1"
     }
     return newObj
 }
 ​
 let me = giveMeInheritance(person)

寄生式组合继承

  1. 一个需要继承的父类(函数),为父类原型添加方法

  2. 一个子类函数,在子类里调用父函数,call改变指向

  3. 写寄生继承的函数f

    1. 传入子类和父类
    2. let 临时对象 = 创建父类原型的一个副本
    3. 使临时对象的构造函数=子类
    4. 子类的原型对象= 临时对象
  4. 调用寄生继承的函数f

  5. (如果喜欢可以给子函数的原型增加一些方法)

  6. (new子函数 获得实例)

实现
 function father(name){
     this.name = name
 }
 father.prototype.say = function(){
     return this.name
 }
 function son(name,age){
     father.call(this,name)
     this.age=age
 }
 ​
 function inherit(son,father){
     let prototype1 = Object.create(father.prototype)
     prototype1.constructor = son
     son.prototype = prototype1
 }
 ​
 inherit(son,father)

Es6 extands继承