前端思考日记(2021/1/22)
写下自己的思考是个好习惯,可以总结自己的学习和智慧,巩固知识,也可以让自己不犯同样错误。希望自己可以坚持下来。
继承问题
本质上来说继承就是把子类的原型连接到父类的原型后面,然后子类生成的实例要有父类生成的实例的属性
如此一来子类可以拥有父类的所有功能
但是继承的时候会有一大堆坑,用的时候肯定是直接使用ES6的class关键字的
这里就是稍微总结一下手写类继承的坑
坑有哪些?
1.把父类的实例属性继承到了原型链上(原型链继承)
function Super () {
this.ability = "念力"
this.equipment = ['念力增幅戒指']
}
Super.prototype.showAbility = function () {
console.log(this.ability,this.equipment);
}
function Sub (name) {
this.name = name
}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
Sub.prototype.introduce = function () {
console.log("my name is " + this.name);
}
const sup = new Super()
const sub = new Sub('superman')
const sub2 = new Sub('superwoman')
sub.equipment.push('念力增幅耳环')
sup.showAbility() // 念力 [ '念力增幅戒指' ]
// sup.introduce() // sup.introduce is not a function
sub.showAbility() // 念力 [ '念力增幅戒指', '念力增幅耳环' ]
sub2.showAbility() // 念力 [ '念力增幅戒指', '念力增幅耳环' ]
sub.introduce() // my name is superman
sub2.introduce() // my name is superwoman
这样继承乍一看所有功能都齐全了,但是因为把父类的实例属性继承到了原型上,会出现一些问题
每一个子类的实例都是共用一个父类的实例为原型
如果父类实例的属性中有引用类型
一个子类实例修改了继承来的引用类型数据,所有子类实例都会受到影响
这大概率是我们不想要的,因为实例属性的继承应该是每个子类实例都独自有一份的
2.修改构造函数的this指向
function Super () {
this.ability = "念力"
this.equipment = ['念力增幅戒指']
}
Super.prototype.showAbility = function () {
console.log(this.ability, this.equipment);
}
function Sub (name) {
Super.call(this)
this.name = name
}
const sub = new Sub('superman')
// sub.showAbility() // sub.showAbility is not a function
console.log(sub.name, sub.ability, sub.equipment) // superman 念力 [ '念力增幅戒指' ]
这样继承的问题很明显,没有把父类的原型继承下来。
而且如果父类写的垃圾,带有实例里面带有函数之列的,子类也会继承下来。
3.组合继承
function Super () {
this.ability = "念力"
this.equipment = ['念力增幅戒指']
}
Super.prototype.showAbility = function () {
console.log(this.ability,this.equipment);
}
function Sub (name) {
Super.call(this)
this.name = name
}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
Sub.prototype.introduce = function () {
console.log("my name is " + this.name);
}
const sub = new Sub('superman')
const sub2 = new Sub('superwoman')
sub.equipment.push('念力增幅耳环')
sub.showAbility() // 念力 [ '念力增幅戒指', '念力增幅耳环' ]
sub2.showAbility() // 念力 [ '念力增幅戒指' ]
sub.introduce() // my name is superman
sub2.introduce() // my name is superwoman
组合继承就是把之前两种进行组合,集合了两者的优点,把之前的缺点都互补解决了
但是可以看到父类的构造函数被调用了两次,性能上不是最优解
想到了一个写法
function Super () {
this.ability = "念力"
this.equipment = ['念力增幅戒指']
}
Super.prototype.showAbility = function () {
console.log(this.ability,this.equipment);
}
function Sub (name) {
Super.call(this)
this.name = name
}
Sub.prototype.__proto__ = Super.prototype
Sub.prototype.introduce = function () {
console.log("my name is " + this.name);
}
const sub = new Sub('superman')
const sub2 = new Sub('superwoman')
sub.equipment.push('念力增幅耳环')
sub.showAbility() // 念力 [ '念力增幅戒指', '念力增幅耳环' ]
sub2.showAbility() // 念力 [ '念力增幅戒指' ]
sub.introduce() // my name is superman
sub2.introduce() // my name is superwoman
子类的 prototype 其实只需要连接在父类的 prototype 的后面就完成了它的工作
那么直接把子类的 prototype.__proto__
连接到父类的prototype后面即可
不知道这样会不会有其他问题,以后遇到了就回来修改