捋一捋js面向对象的继承问题
程序员文章站
2022-03-10 18:27:26
说到面向对象这个破玩意,曾经一度我都处于很懵逼的状态,那么面向对象究竟是什么呢?其实说白了,所谓面向对象,就是基于类这个概念,来实现封装、继承和多态的一种编程思想罢了。今天我们就来说一下这其中继承的问题。 好,先不直接上代码,而是反手来一波文字说明,捋一捋思路。 曾经一段时间因为javascript ......
说到面向对象这个破玩意,曾经一度我都处于很懵逼的状态,那么面向对象究竟是什么呢?其实说白了,所谓面向对象,就是基于类这个概念,来实现封装、继承和多态的一种编程思想罢了。今天我们就来说一下这其中继承的问题。
好,先不直接上代码,而是反手来一波文字说明,捋一捋思路。
曾经一段时间因为javascript关于类实现继承的不规范,导致各种各样实现继承的代码;而实际上不管代码怎么变,继承都基于两种方式:
1.通过原型链,即子类的原型指向父类的实例从而实现原型共享。
2.借用构造函数,即通过js的apply、call实现子类调用父类的属性、方法;
原型链方式可以实现所有属性方法共享,但无法做到属性、方法独享(例如son1指向的是父类实例,son2,son3同样如此,大家都是吃的同一碗饭);
而借用构造函数除了能独享属性、方法外还能在子类构造函数中传递参数,但代码无法复用。总体而言就是可以实现所有属性方法独享,但无法做到属性、方法共享(例如,son1新增了一个函数,然后想让son2、son3一起用的话就无法实现了,只能son2,son3各自在构造函数中新增)。
组合继承就是把以上两种继承方式一起使用,把共享的属性、方法用原型链继承实现,独享的属性、方法用借用构造函数实现,所以组合继承几乎完美实现了js的继承;
为什么说是“几乎”?因为后来人们发现组合继承有一个小bug,实现的时候调用了两次父类,性能上不合格啊有木有!怎么解决呢?于是“寄生继承”就出来了。
简单而言,寄生继承就是不用实例化父类了,直接实例化一个临时副本实现了相同的原型链继承。(即子类的原型指向父类原型的副本),如此一来,这个问题就完美解决了。
接下来是代码部分:
这里我们通过apply方法给儿子传了私有属性,但是父类原型上的方法是无法调用的。
然后我们试试通过原型链来实现继承。
这样一来就把父类的全部东西都一股脑继承下来了,而且我这里如果Sons修改了父类的原型,其他跟着用的比如Daughters也要跟着遭殃。
而组合继承这时候就出来了,组合继承就是把以上两种继承方式一起使用,把共享的属性、方法用原型链继承实现;独享的属性、方法用借用构造函数实现。至于寄生组合继承,它是为了解决组合继承会二次调用父类这个bug出现的优化方法,具体实现如下:
在这一步,无论是儿子还是女儿,都能成功调用父类的公用方法。接着在末尾添加两行代码往下看:
两个say方法虽然同名,却互不影响。最后调用父类的私有属性看看:
只有儿子利用私有属性拿到了secret,而女儿没有拿到,完美解决共享与独享分配的问题!