IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 继承模式——JS -> 正文阅读

[JavaScript知识库]继承模式——JS

继承模式

先搭建好继承框架:

        // 父类型
        function Supper (){
           this.supProp = 'Supper property'
        }
        Supper.prototype.showSupperPop = function (){
           console.log(this.supProp)
        }

        // 子类型
        function Sub (){
           this.subProp = 'Sub property'
        }
        Sub.prototype.showSubPop = function (){
           console.log(this.subProp)
        }

        var sub = new Sub()
        sub.showSupperPop()//想要实现调用,当然现在这样写是错误的

原型链继承

首先思考如何能够看到 Supper的showSupperPop方法

  • 利用原型链
    如果子类型的原型对象成为父类型的一个实例对象,子类型就可以通过原型链看到父类型的属性和方法了,即实现了继承。
    对应代码:Sub.prototype = new Supper()

解释:
上面代码的原型链:
在这里插入图片描述
如果想要sub实例可以访问Supper原型对象的showSupperPop(),就需要有一个箭头从 sub原型对象的__proto__指向 Supper的原型对象。即,使子类型的原型对象成为父类型的一个实例对象。
可能会问为什么不直接 从 sub实例对象的 __proto__指向 Supper的原型对象,如果这样的话,子类型的属性和方法就访问不到了。
注意,一个对象的 proto 只能存一个值。

(这里先这样理解,实际上真正实现继承不单单只是将sub原型对象的__proto__的指向改变了,可以看下面实际操作一步步画出的原型链进行理解。)

实现:
将子类型的原型对象定义为父类型的实例对象

        // 父类型
        function Supper (){
           this.supProp = 'Supper property'
        }
        Supper.prototype.showSupperPop = function (){
           console.log(this.supProp)
        }

        // 子类型
        function Sub (){
           this.subProp = 'Sub property'
        }
        // 子类型的原型成为夫类型的实例对象
        Sub.prototype = new Supper()
        Sub.prototype.showSubPop = function (){
           console.log(this.subProp)
        }

        var sub = new Sub()
        sub.showSupperPop()
        sub.showSubPop()
        console.log(sub.toString()) 

输出:
在这里插入图片描述
此时对应的原型链:
在这里插入图片描述

问题

问题产生

constructor属性返回对象的构造函数。
那么上面的代码如果执行console.log(sub.constructor),会是什么结果呢

        // 父类型
        function Supper (){
           this.supProp = 'Supper property'
        }
        Supper.prototype.showSupperPop = function (){
           console.log(this.supProp)
        }
        // 子类型
        function Sub (){
           this.subProp = 'Sub property'
        }

        // 子类型的原型成为夫类型的实例对象
        Sub.prototype = new Supper()
        Sub.prototype.showSubPop = function (){
           console.log(this.subProp)
        }

        var sub = new Sub()
      //    constructor属性返回对象的构造函数
        console.log(sub.constructor)

输出:
在这里插入图片描述
输出的是Supper而不是我们预想的Sub,这是什么原因呢?
还是看刚才的原型链:sub实例对象没有constructor属性,就会像上找找到Supper的实例对象,发现也没有该属性,继续上找,找到Supper的原型对象发现有该属性,并且指向Supper的函数对象,所以输出就是Supper的函数对象。
在这里插入图片描述

问题解决

我们一般让对象的constructor指向自己的原型对象,所以做如下修改:
// 让子类型原型对象的constructor属性指向Sub
Sub.prototype.constructor = Sub
代码:

        // 父类型
        function Supper (){
           this.supProp = 'Supper property'
        }
        Supper.prototype.showSupperPop = function (){
           console.log(this.supProp)
        }
        // 子类型
        function Sub (){
           this.subProp = 'Sub property'
        }

        // 子类型的原型成为夫类型的实例对象
        Sub.prototype = new Supper()
      //   让子类型原型对象的constructor属性指向Sub
        Sub.prototype.constructor = Sub
        Sub.prototype.showSubPop = function (){
           console.log(this.subProp)
        }

        var sub = new Sub()

      //    constructor属性返回对象的构造函数
        console.log(sub.constructor)

输出:
在这里插入图片描述

对应的原型链:
在这里插入图片描述

借用构造函数继承——不是真正的继承

方法:
1.定义父类型构造函数
2.定义子类型构造函数
3.在子类型构造函数中调用父类型构造,利用函数的call方法
call方法的作用就是短暂的调用一个不属于自己的函数。
eg:

        function Person (name ,age){
           this.name = name
           this.age =age
        }
        function Student (name,age,price){
           Person.call(this,name,age)   
        /*
        含义相当于 this.Person(name,age)
        即:
           this.name = name
           this.age =age
        (注意this.Person(name,age)这句话不能执行,this没有Person属性,这样写只是为了方便理解)
        */
            this.price = price
        }
        var s =new Student('Tom',12,10000)
        console.log(s.name,s.age,s.price)

输出:
在这里插入图片描述

组合继承

组合继承就是将原型链继承和借用构造函数继承结合起来。

  • 利用原型链实现对父类型对象的方法继承
  • 利用call()借用父类型构造函数初始化相同属性
    eg:
        function Person (name ,age){
           this.name = name
           this.age =age
        }
        Person.prototype.setName=function(name){
            this.name = name
        }


        function Student (name,age,price){
            // 借用父类型构造函数初始化相同属性
            //使用call,下面Student.prototype = new Person()就无需传参了
           Person.call(this,name,age)   
            this.price = price
        }
        // 继承原型链,继承父类型对象的方法继承
        //因为上面使用Person.call(this,name,age),这里就无需传参了  
        Student.prototype = new Person()
        // 修正constructor属性
        Student.prototype.constructor =Student

        Student.prototype.setPrice=function(price){
            this.setPrice = price
        }
        var s = new Student('Tom',24,10000)
        s.setPrice(16000)
        s.setName('Bob')
        console.log(s.name,s.age,s.price)

输出:
在这里插入图片描述

我们通常使用的是组合继承

  • 为什么不使用原型链继承?
    因为夫类型的构造函数一般是要传递参数的,而我们使用 Sub.prototype = new Supper()只是为了建立原型链的关系,一般不需要传参,就出现了矛盾。

如果执意不传参,就会出现如下错误:

        function Person (name ,age){
           this.name = name
           this.age =age
        }
        Person.prototype.setName=function(name){
            this.name = name
        }


        function Student (name,age,price){
            // 借用父类型构造函数初始化相同属性
        //    Person.call(this,name,age)  
            this.name =name
            this.age =age
            this.price = price
        }
        // 继承原型链,继承父类型对象的方法继承
        Student.prototype = new Person()
        // 修正constructor属性
        Student.prototype.constructor =Student

        Student.prototype.setPrice=function(price){
            this.setPrice = price
        }
        var s = new Student('Tom',24,10000)
        s.setName('Bob')
        s.setPrice(16000)
        console.log(s.name,s.age,s.price)

输出:
在这里插入图片描述

  • 为什么不使用借用构造函数继承?
    因为他只是表面上的简单引用,原型链上的方法属性不会继承。

所以使用两种方式相结合的方法实现组合继承:
在子类型的构造函数中使用 父构造函数.call(this,参数),下面再将子类型的原型修改为父类型的实例的时候就无需传参了 。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 12:02:02  更:2022-04-29 12:02:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:09:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码