JavaScript组合继承详解


Posted in Javascript onNovember 07, 2021

1、前言

首先学习继承之前,要对原型链有一定程度的了解。

不了解可以去先阅读我另一篇文章,里面对原型链有一个较为详细的说明:JavaScript 原型链详解。

如果已经了解请继续。

之前写过一篇博文将继承方式全部列出来了,不过我发现一口气看完过于长了,也不利于吸收知识,所以我先将组合继承部分划分出来,后续会把寄生部分补上。

2、原型链继承

父类实例作为子类的原型
子类创造的两个实例的隐式原型__proto__指向父类的那个实例
而父类的实例的隐式原型__proto__又指向父类的原型father.prototype
根据原型链的特性,所有子类的实例能够继承父类原型上的属性。

阅览以下这张图可以配合代码理解清晰:

JavaScript组合继承详解

   

//父类
    function father() {
      this.fatherAttr = ["fatherAttr"];
    }
    
    //父类的原型上的属性
    father.prototype.checkProto = "checkProto";

    //子类
    function child() {}

    // 将father实例作为child这个构造函数的原型
    child.prototype = new father();
    child.prototype.constructor = child;

    //两个子类实例
    const test1 = new child();
    const test2 = new child();

    console.log("测试1:");
    console.log("test1:", test1);
    console.log("test2:", test2);
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);

    console.log("测试2:");
    test1.fatherAttr.push("newAttr");
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);

    console.log("测试3:");
    console.log("test1.checkProto:", test1.checkProto);

JavaScript组合继承详解

特点:

  • 两个实例对象都没有fatherAttr属性,但是因为父类的实例会拥有fatherAttr属性,且现在父类的实例作为child的原型,根据原型链,他们可以共享到自己的构造函数child的原型上的属性。(测试1)
  • 因为只有一个父类的实例作为他们的原型,所以所有实例共享了一个原型上的属性fatherAttr,当原型上的属性作为引用类型时,此处是数组,test1添加一个新内容会导致test2上的fatherAttr也改变了。(测试2)(缺点)
  • child构造函数不能传递入参。(缺点)
  • 实例可以访问到父类的原型上的属性,因此可以把可复用方法定义在父类原型上。(测试3)

3、构造函数继承

将父类上的this绑定到子类,也就是当子类创造实例时会在子类内部调用父类的构造函数,父类上的属性会拷贝到子类实例上,所以实例会继承这些属性。

//父类
    function father(params) {
      this.fatherAttr = ["fatherAttr"];
      this.params = params;
    }

    //父类的原型上的属性
    father.prototype.checkProto = "checkProto";

    //子类
    function child(params) {
      father.call(this, params);
    }

    //两个子类实例
    const test1 = new child("params1");
    const test2 = new child("params2");

    console.log("测试1:");
    console.log("test1:", test1);
    console.log("test2:", test2);
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);

    console.log("测试2:");
    test1.fatherAttr.push("newAttr");
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);
    
    console.log("测试3:");
    console.log("test1.checkProto:", test1.checkProto);

JavaScript组合继承详解

特点:

  • 两个实例对象都拥有了拷贝来的fatherAttr属性,所以没有共享属性,创造一个实例就得拷贝一次父类的所有属性,且因为不能继承父类原型,所以方法不能复用,被迫拷贝方法。(测试1)(缺点)
  • test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(测试2)
  • child构造函数可以传递参数,定制自己的属性。(测试1)
  • 实例不能继承父类的原型上的属性。(测试3)(缺点

4、组合继承

结合原型链继承和构造函数继承,可以根据两种继承特点进行使用。

//父类
    function father(params) {
      this.fatherAttr = ["fatherAttr"];
      this.params = params;
    }

    //父类的原型上的属性
    father.prototype.checkProto = "checkProto";

    //子类
    function child(params) {
      //第二次调用了父类构造函数
      father.call(this, params);
    }

    // 将father实例作为child构造函数的原型
    child.prototype = new father();//第一次调用了父类构造函数
    child.prototype.constructor = child;

    //两个实例
    const test1 = new child("params1");//从这里跳转去子类构造函数第二次调用了父类构造函数
    const test2 = new child("params2");

    console.log("测试1:");
    console.log("test1:", test1);
    console.log("test2:", test2);
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);

    console.log("测试2:");
    test1.fatherAttr.push("newAttr");
    console.log("test1.fatherAttr:", test1.fatherAttr);
    console.log("test2.fatherAttr:", test2.fatherAttr);

    console.log("测试3:");
    console.log("test1.checkProto:", test1.checkProto);

    console.log("测试4:");
    delete test1.fatherAttr
    console.log("test1:", test1);
    console.log("test1.fatherAttr:", test1.fatherAttr);

JavaScript组合继承详解

特点:

  • 两个实例对象都拥有了拷贝来的fatherAttr属性,创造一个实例就得拷贝一次父类的所有属性(构造函数继承特点,测试1),但是能访问父类原型,可以把复用方法定义在父类原型上。(原型链继承特点,测试1)
  • test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(构造函数继承特点,测试2)
  • child构造函数可以传递参数,定制自己的属性。(构造函数继承特点,测试1)
  • 实例能继承父类的原型上的属性。(原型链继承特点,测试3)
  • 调用了两次父类的构造函数,生成两份实例,创建子类原型链一次,用子类创建实例时,子类内部里面一次,第二次覆盖了第一次。(缺点)
  • 因为调用两次父类构造函数,如果用delete删除实例上拷贝来的fatherAttr属性,实例仍然拥有隐式原型指向的父类实例上的fatherAttr属性。(原型链继承特点,测试4)(缺点)

到此这篇关于JavaScript组合继承详解的文章就介绍到这了,更多相关JavaScript组合继承内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
基于jquery的一个简单的脚本验证插件
Apr 05 Javascript
Jquery 扩展方法
May 06 Javascript
Javascript 面向对象 对象(Object)
May 13 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
Feb 26 Javascript
div失去焦点事件实现思路
Apr 22 Javascript
JavaScript中标识符提升问题
Jun 11 Javascript
Javascript 正则表达式校验数字的简单实例
Nov 02 Javascript
Mongoose经常返回e11000 error的原因分析
Mar 29 Javascript
vue中axios处理http发送请求的示例(Post和get)
Oct 13 Javascript
微信小程序开发之tabbar图标和颜色的实现
Oct 17 Javascript
jQuery实现的自定义轮播图功能详解
Dec 28 jQuery
JS利用prototype给类添加方法操作详解
Jun 21 Javascript
详细聊聊vue中组件的props属性
教你一步步实现一个简易promise
Nov 02 #Javascript
一定要知道的 25 个 Vue 技巧
原型和原型链 prototype和proto的区别详情
Nov 02 #Javascript
浅谈克隆 JavaScript
Nov 02 #Javascript
WebWorker 封装 JavaScript 沙箱详情
quickjs 封装 JavaScript 沙箱详情
Nov 02 #Javascript
You might like
php中看实例学正则表达式
2006/12/25 PHP
PHP实现根据浏览器跳转不同语言页面代码
2013/08/02 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十一)
2014/06/25 PHP
php使用$_POST或$_SESSION[]向js函数传参
2014/09/16 PHP
PHP 7安装使用体验之性能大提升,兼容性强,扩展支持不够(升级PHP要谨慎)
2017/07/27 PHP
PHP生成随机数的方法总结
2018/03/01 PHP
php实现的表单验证类完整示例
2019/08/13 PHP
js变量作用域及可访问性的探讨
2006/11/23 Javascript
腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
2010/07/26 Javascript
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
JavaScript获取FCK编辑器信息的具体方法
2013/07/12 Javascript
jquery转盘抽奖功能实现
2015/11/13 Javascript
jQuery短信验证倒计时功能实现方法详解
2016/05/25 Javascript
最原始的jQuery注册验证方式
2016/10/11 Javascript
Mongoose学习全面理解(推荐)
2017/01/21 Javascript
jQuery使用siblings获取某元素所有同辈(兄弟姐妹)元素用法示例
2017/01/30 Javascript
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
2017/03/23 jQuery
详解使用vuex进行菜单管理
2017/12/21 Javascript
JavaScript对象的浅拷贝与深拷贝实例分析
2018/07/25 Javascript
微信小程序 slot踩坑的解决
2019/04/01 Javascript
vuejs数据超出单行显示更多,点击展开剩余数据实例
2019/05/05 Javascript
Element中Slider滑块的具体使用
2020/07/29 Javascript
[47:38]Optic vs VGJ.S 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python中import reload __import__的区别详解
2017/10/16 Python
Python构建网页爬虫原理分析
2017/12/19 Python
Flask入门之上传文件到服务器的方法示例
2018/07/18 Python
django之自定义软删除Model的方法
2019/08/14 Python
numpy 声明空数组详解
2019/12/05 Python
详解Python中pyautogui库的最全使用方法
2020/04/01 Python
python如何输出反斜杠
2020/06/18 Python
4款Python 类型检查工具,你选择哪个呢?
2020/10/30 Python
美国著名首饰网站:BaubleBar
2016/08/29 全球购物
婚纱摄影师求职信范文
2014/04/17 职场文书
大学新生军训自我鉴定
2014/09/18 职场文书
大学生自荐材料范文
2014/12/30 职场文书
【海涛教你打DOTA】死灵飞龙第一视角解说
2022/04/01 DOTA