!
也想出现在这里? 联系我们
广告区块

【JavaScript 进阶教程】非 extends 的组合继承

? 欢迎继续来到 JavaScript 进阶教学!

继承也是面向对象的特性之一,但是在 ES6 版本之前是没有 extends 去实现继承的,我们只能通过 构造函数 原型对象 来实现继承,其中分别为构造函数来继承属性,原型对象来继承方法,这种继承模式被称为 组合继承


【JavaScript 进阶教程】非 extends 的组合继承


文章目录:

一:call() 的作用与使用

1.1 使用 call() 来调用函数

1.2 使用 call() 来改变 this 的指向

二:利用构造函数继承父属性

2.1 实现过程

2.1 实现过程分析

三:利用原型对象继承父方法

3.1 继承父方法的错误演示

问题原因

3.2 继承父方法的正确做法

3.2 继承父方法的注意事项


一:call() 的作用与使用

在开始讲解组合继承前我们先来了解一下 call() 方法,call() 方法可以改变 this 的指向,也可以调用函数等等,最主要的还是其改变指向的作用

语法格式 call( 目标this指向,参数1,参数2 ……)

1.1 使用 call() 来调用函数

call() 可以拿来直接用来调用函数

  1. function eat(){
  2. console.log('我在吃午饭');
  3. }
  4. eat.call()

【JavaScript 进阶教程】非 extends 的组合继承


1.2 使用 call() 来改变 this 的指向

call() 的第一个参数为你要改变的 this 的指向,这里的 this 指的是 call 的调用者,此处函数调用不指定的话即指向 window,指定让其指向新创建的对象 obj,只需要让其第一个参数为 obj 对象即可,所以结果应该是第一个为 window,第二个为 obj 对象

  1. function eat(){
  2. console.log(this);
  3. }
  4. var obj={
  5. 'name':'小明',
  6. 'age':18
  7. }
  8. eat.call()
  9. eat.call(obj)

【JavaScript 进阶教程】非 extends 的组合继承


二:利用构造函数继承父属性

我们已经知道组合继承是由构造函数和原型对象一起来实现的,其中构造函数实现的是属性的继承,原型对象实现的是方法的继承,这版块就走进利用父构造函数完成属性的继承

【JavaScript 进阶教程】非 extends 的组合继承

2.1 实现过程

其实现非常容易,只需要在子构造函数中,使用 call 调用父构造函数(将其当做普通函数调用),其中在 call 方法中更改父构造函数中的 this 指向,由于 call 方法是在子构造函数中调用的,所以此处当做参数的 this 代表父构造函数中的 this 指向子构造函数的实例化对象,并传参进去,所以相当于给子构造函数的实例化对象添加了属性并赋值

  1. //声明父构造函数
  2. function Father(uname,uage,utel,sex){
  3. this.uname=uname;
  4. this.uage=uage;
  5. this.utel=utel;
  6. this.sex=sex;
  7. }
  8. //声明子构造函数,但是想继承父类的uname,uage,utel等等属性的赋值操作
  9. function Son(uname,uage,utel,sex){
  10. Father.call(this,uname,uage,utel,sex)
  11. }
  12. var son1=new Son('张三',19,12345,'男')
  13. console.log(son1);

【JavaScript 进阶教程】非 extends 的组合继承


2.1 实现过程分析

  • 首先在子构造函数中使用 call 调用了父构造函数,并传参给 call 的参数,其中第一个参数为 this 指向的改变,其余为带入的属性值参数
  • 我们知道构造函数中的 this 指向其实例化对象,所以本身父构造函数的 this 应该指向父构造函数的实例化对象,而此处 call 方法调用在子构造函数中,所以参数的指向更改为指向子构造函数的实例化对象
  • 此处子构造函数的实例化对象就是 son1,所以父构造函数中的 this 指向的均是 son1,
  • 所以就给 son1 添加并赋值了 uname,uage 等等属性

【JavaScript 进阶教程】非 extends 的组合继承


三:利用原型对象继承父方法

组合继承的最后一版块,利用原型对象来继承方法,此处我们说明的是存放在构造函数的原型对象里的公共方法的继承

3.1 继承父方法的错误演示

错误的继承就是直接将父亲的原型对象赋值给子的原型对象,这样确实也可行,但是如果给子原型对象添加子类特有的方法,那父原型对象也会加上这个方法

  1. //声明父构造函数
  2. function Father(uname,uage){
  3. this.uname=uname;
  4. this.uage=uage;
  5. }
  6. Father.prototype.money=function(){
  7. console.log('我有很多钱');
  8. }
  9. //声明子构造函数
  10. Son.prototype=Father.prototype;
  11. function Son(uname,uage){
  12. Father.call(this,uname,uage)
  13. }
  14. var father1=new Father('爸爸',40)
  15. var son1=new Son('儿子',19)
  16. console.log(father1);
  17. console.log(son1);
【JavaScript 进阶教程】非 extends 的组合继承

我们可以发现父子的原型对象中确实都有了这个方法,证明确实这个办法是行得通的

【JavaScript 进阶教程】非 extends 的组合继承

但是其也有问题存在,当我们想给子原型对象单独添加其特有的方法时,就会出问题

  • 上述问题给子原型对象添加特有方法的错误示例:

  1. //声明父构造函数
  2. function Father(uname,uage){
  3. this.uname=uname;
  4. this.uage=uage;
  5. }
  6. Father.prototype.money=function(){
  7. console.log('我有很多钱');
  8. }
  9. //声明子构造函数
  10. Son.prototype=Father.prototype;
  11. Son.prototype.school=function(){
  12. console.log('我去上学了');
  13. }
  14. function Son(uname,uage){
  15. Father.call(this,uname,uage)
  16. }
  17. var father1=new Father('爸爸',40)
  18. var son1=new Son('儿子',19)
  19. console.log(father1);
  20. console.log(son1);
【JavaScript 进阶教程】非 extends 的组合继承

我们发现,我们确实给儿子添加上了儿子特有的方法,但是,父亲的原型对象内也加上了这个方法,这并不满足我们的预期,原因分析如下

【JavaScript 进阶教程】非 extends 的组合继承

  • 问题原因

问题就在于我们的原型对象也是对象,对象是引用数据类型,引用数据类型的对象本质是在堆内存存放,是不能直接访问的,其访问是通过栈内存上的引用地址来找到去访问,而我们此处采用的等号赋值的方式,实际上是将其在栈内存上的引用地址拷贝过去了,二者指向了同一块内存空间,所以更改子原型对象,父原型对象也改变了

【JavaScript 进阶教程】非 extends 的组合继承


3.2 继承父方法的正确做法

正确的做法是让其子原型对象对象等于父实例化对象 Son.prototype=new Father(),其实我感觉有种高内聚低耦合的韵味,减少了直接联系从而解决问题

【JavaScript 进阶教程】非 extends 的组合继承

  1. //声明父构造函数
  2. function Father(uname,uage){
  3. this.uname=uname;
  4. this.uage=uage;
  5. }
  6. Father.prototype.money=function(){
  7. console.log('我有很多钱');
  8. }
  9. //声明子构造函数
  10. Son.prototype=new Father();
  11. Son.prototype.school=function(){
  12. console.log('我去上学了');
  13. }
  14. function Son(uname,uage){
  15. Father.call(this,uname,uage)
  16. }
  17. var father1=new Father('爸爸',40)
  18. var son1=new Son('儿子',19)
  19. console.log(father1);
  20. console.log(son1);
【JavaScript 进阶教程】非 extends 的组合继承

问题得以解决,子原型对象有了自己特有的方法,并且也继承了父亲原型对象中的方法

【JavaScript 进阶教程】非 extends 的组合继承


3.2 继承父方法的注意事项

我们以 Son.prototype=new Father() 这种方法继承,看似已经天衣无缝,其实我们早就说过,采用等号赋值的方法会造成原型对象被覆盖,里面的构造函数 constructor 会被覆盖掉,需要我们手动返回,所以七千万要记得手动返回 constructor

  1. //声明父构造函数
  2. function Father(uname,uage){
  3. this.uname=uname;
  4. this.uage=uage;
  5. }
  6. Father.prototype.money=function(){
  7. console.log('我有很多钱');
  8. }
  9. //声明子构造函数
  10. Son.prototype=new Father();
  11. Son.prototype.constructor=Son; //手动返回构造函数constructor
  12. Son.prototype.school=function(){
  13. console.log('我去上学了');
  14. }
  15. function Son(uname,uage){
  16. Father.call(this,uname,uage)
  17. }
  18. var father1=new Father('爸爸',40)
  19. var son1=new Son('儿子',19)
  20. console.log(father1);
  21. console.log(son1);
  22. console.log(Son.prototype.constructor);
【JavaScript 进阶教程】非 extends 的组合继承

【JavaScript 进阶教程】非 extends 的组合继承

感谢阅读,下篇更精彩!!!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_52212950/article/details/125989533
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
有新私信 私信列表
搜索