前端思考日记(2021/1/22)

本文探讨了JavaScript中手写类继承的常见坑,包括原型链继承导致的属性共享问题、构造函数this指向调整,以及组合继承的性能开销。作者提出通过`__proto__`连接子类到父类原型来改进,以确保实例属性独立且性能更优。
摘要由CSDN通过智能技术生成

前端思考日记(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后面即可

不知道这样会不会有其他问题,以后遇到了就回来修改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>