[Js茶话会]-Class继承(不信看完还不懂)

287 阅读3分钟

class继承

继承的实现方法五花八门,随便百度一下,都有好几种实现方式,幸好Es6用实现了继承的语法糖。我们先看看Es6的继承有哪些特点

Es6的继承

function Father() { 
    this.name = 'father'
};
Father.prototype.age = 100;

class ClassSon extends Father {
}
let classSon = new ClassSon();

console.log('classSon name', classSon.name//fater
console.log('classSon age', classSon.age// 100
console.log('classSon instanceof ClassSon', classSon instanceof ClassSon// true
console.log('classSon instanceof Father', classSon instanceof Father//true
console.log('classSon', classSon)

接下来我们一步一步实现Es6的class

实例继承

  • 实例赋值原型,这样不仅把Father的name属性给了SonA,还把原型属性也给了SonA,因为Fahter实例上包含Fathe的原型属性
function Father() {
    this.name = 'father'
};
Father.prototype.age = 100;

function SonA() {
}

SonA.prototype = new Father()
let classSon = new SonA()
console.log('SonA name', classSon.name//fater
console.log('SonA age', classSon.age// 100
console.log('SonA instanceof SonA', classSon instanceof SonA// true
console.log('SonA instanceof Father', classSon instanceof Father//true
console.log('SonA', classSon)
  • 看起来很美好,所有的用例都过了。但是有一个最明显的缺陷,那就是无法把子类构造函数的参数传给父类
  • 在看下打印出来的子类实例,也有问题:name属性不在SonA的实例上; SonA的constructor指向父类

call借用父类的构造函数属性

function Father() {
    this.name = 'father'
};
Father.prototype.age = 100;

function SonB(name) {
    Father.call(this,name)
}
const classSon = new SonB()
console.log('SonB name', classSon.name//fater
console.log('SonB age', classSon.age// undefined
console.log('SonB instanceof SonB', classSon instanceof SonB// true
console.log('SonB instanceof Father', classSon instanceof Father//false
console.log('SonB', classSon)
  • Father.call(this,name)。大家都知道call的作用是改变this的指向。那么这句话的意思就是把Fahter里面的实例属性都指向给了SonB。所以相当于给了SonB的实例增加了属性
  • 看下打印的实例:有name属性,construct也指向正确,但是和Father没有啥关系了,所以仅仅借用Father的属性也是不行的 db082c5a464a9bdd37884718b40b5774.png
  • 从这里看出完成了部分功能,但是原型属性没有继承,并且与Father没有联系。接下来我们看看能否增强上面的代码

原型赋予

  • 上面的例子中,原型没有赋予给子类,我们可以尝试把原型直接丢给子类原型
function Father() {
    this.name = 'father'
};
Father.prototype.age = 100;
function SonC(name) {
    Father.call(this,name)
}
SonC.prototype = Father.prototype
  • 但是这样的有个很大的缺陷,就是修改SonC的原型的同时,也会修改Father的原型。这不符合面向对象的逻辑,所以我们需要一个中介来实现这个赋予功能

寄生

  • Object有个Api: Object.create,MDN的解释是创建一个对象,让他的__proto__指向另一个对象。这样一看很符合咱们的要求。
function Father() {
    this.name = 'father'
};
Father.prototype.age = 100;

function SonB(name) {
    Father.call(this,name)
}
// 创建一个寄生器
const pro= Object.create(Father.prototype)
/**
也有种创建方法,其实意思都一样
const Super = function(){}
Super.prototype = Father.prototype
SonB.prototype = new Super()
SonB.prototype.constructor = SonB
**/
//修复构造函数指向
pro.constructor = SonB
//原型赋予
SonB.prototype = pro
const classSon = new SonB()
console.log('SonB name', classSon.name//fater
console.log('SonB age', classSon.age// 100
console.log('SonB instanceof SonB', classSon instanceof SonB// true
console.log('SonB instanceof Father', classSon instanceof Father//true
console.log('SonB', classSon)
  • 看下实例,与es6相同,实现完成