Js几种继承方式及分析

这是我参与更文挑战的第16天,活动详情查看:更文挑战

盗用构造函数

  • 在子类的构造函数中,使用call()来调用父类的构造函数
function SuperType(name) {
  this.name = name
  console.log(this)
}
SuperType.prototype.getName = function () {
  return this.name
}

function SubType() {
  // 继承 SuperType 并传参
  SuperType.call(this, 'Nicholas')
  // 实例属性
  this.age = 29
}


let instance = new SubType()
console.log(instance)

复制代码
  • call()方法用来改变this的指向,这里在SubType中执行SuperType,将this传递过去

image-20210623191027254

  • 这种方式只能继承父类的属性,不能访问原型上定义的属性方法
SuperType.prototype.getName = function () {
  return this.name
}

console.log(instance.getName()) //Uncaught TypeError:
复制代码

组合继承

  • 继承原型对象的属性和方法,通过call()盗用构造函数,继承构造函数中的属性和方法
function SuperType(name) {
  this.name = name
  this.colors = ['red', 'black']
}

SuperType.prototype.sayName = function () {
  console.log(this.name)
}

function SubType(name, age) {
  SuperType.call(this, name)
  this.age = age
}

SubType.prototype = new SuperType()
SubType.prototype.sayAge = function () {
  console.log(this.age)
}
let instance1 = new SubType('Nicholas', 29)
console.log(instance1)
instance1.colors.push('black')
console.log(instance1.colors) // "red,blue,green,black"
instance1.sayName() // "Nicholas";
instance1.sayAge() // 29
复制代码

image-20210624164633010

分析一下这个对象结构:

首先需要知道,每次创建一个实例对象的时候,都会在实例中创建一个私有属性__proto__指向构造函数的原型对象

  • SubType.prototype = new SuperType(),这里调用SuperType的构造函数,返回了一个实例对象,这个对象里面有两个属性{name:undefined,colors:['red',black]},同有一个__proto__指向了原型对象SuperType.prototype这个原型对象中包含一个sayName()

  • let instance1 = new SubType('Nicholas', 29)创建实例对象,在构造函数SubType中,使用call()来重新指定this,并且调用了父类SuperType,得到了{name:'Nicholas',colors:['red',black]}

    然后执行this.age,添加了一个age属性。同样的他也有__proto__指向了SubType原型对象,这个原型对象上存在一个sayAge方法

组合继承是使用最多的继承模式,填补了盗用构造函数继承模式不能使用父类原型上的方法的缺点

原型式继承

与前面两种模式不同的是,这种继承方式不需要创建构造函数,只需要一个简单的对象

let person = {
  name: 'Nicholas',
  friends: ['Shelby', 'Court', 'Van'],
}
let anotherPerson = Object.create(person)
anotherPerson.name = 'Greg'
anotherPerson.friends.push('Rob')
let yetAnotherPerson = Object.create(person)
yetAnotherPerson.name = 'Linda'
yetAnotherPerson.friends.push('Barbie')
console.log(person) 
console.log(anotherPerson)
console.log(yetAnotherPerson)
复制代码

image-20210624180222530

  • 这里Object.create()返回一个新对象,这个新对象的原型对象是传入的第一个参数

  • 通过控制台可以看到,anotherPerson是创建的一个新对象,然后里面有一个__proto__指向它的原型对象person

原型式继承非常适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合。但要记住,属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的。

寄生式继承

创建一个实现继承的函数,然后传入的对象进行一些操作,然后返回出去

function createAnother(original) {
  let clone = Object.create(original) // 通过调用函数创建一个新对象
  clone.sayHi = function () {
    // 以某种方式增强这个对象
    console.log('hi')
  }
  return clone // 返回这个对象
}

let person = {
  name: 'Nicholas',
  friends: ['Shelby', 'Court', 'Van'],
}
let anotherPerson = createAnother(person)
console.log(anotherPerson)
anotherPerson.sayHi() // "hi"
复制代码

image-20210624191030705

  • 与原型式继承相似,相比与他,寄生式继承知识在外面额外定义了一个函数createAnother(),这本身就是利用工厂函数创建对象
  • 在这个工厂函数内部定义了一个sayHi(),Object.create()返回一个新对象,这个新对象的原型对象是传入的第一个参数

寄生式组合继承

  • 组合式继承是常用的继承方式,但是存在一个缺点,通过产看原型链可以看到,她有的属性会重复存在,在上面的例子中存在两组namecolor属性
  • 而寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路是不通过调
    用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。说到底就是使用寄生式继承来继承父
    类原型,然后将返回的新对象赋值给子类原型。
function inheritPrototype(subType, superType) {
  let prototype = Object.create(superType.prototype) // 创建对象
  prototype.constructor = subType // 增强对象
  subType.prototype = prototype // 赋值对象
}

function SuperType(name) {
  this.name = name
  this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
  console.log(this.name)
}
function SubType(name, age) {
  SuperType.call(this, name)
  this.age = age
}
inheritPrototype(SubType, SuperType)
SubType.prototype.sayAge = function () {
  console.log(this.age)
}

const instance = new SubType('Tom', 22)

console.log(instance)
复制代码

image-20210624194852453

分析一下这个结构:

  • new SubType('Tom', 22)调用SubType()构造函数,遇到call()之后改变this指向去调用SuperType()构造函数,创建了两个属性namecolors,将这个属性挂载到实例对象上,继续执行,挂载age属性,

  • inheritPrototype创建父类原型的一个副本 ,原型对象中包含一个constrcutor属性,这个属性指向构造函数,重新定向prototype属性会造成constructor属性丢失的问题,所以需要重新给新创建的对象添加一个constructor属性

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享