美文网首页前端学习笔记
浅谈 JS 中继承的写法

浅谈 JS 中继承的写法

作者: _ClariS_ | 来源:发表于2019-10-10 22:57 被阅读0次
    JS中的几种流派

    继承是属于面向对象流派

    什么是类

    定义:能产生对象的东西即为“类”

    举个例子

    这里的 Human 就是一个类

    什么是继承

    定义:继承就是描述类和类之间的关系,它可以使得子类别具有父类别的各种属性和方法

    上面的例子中,Human的部分属性继承自Object,这是所有对象都存在的一个自带的继承关系。而Man继承自Human,这是我们自己实现的一个继承关系。

    image.png

    这里要特别注意实例属性与继承的区别

    实例属性与继承的区别

    从上图中可以看出,继承的实质就是进行两次的原型搜索

    另外,只有构造函数有prototype属性,prototype属性只有一个功能就是存放共有属性对象
    的地址

    继承

    ES5实现继承的写法

    如何实现下图中的继承关系

    image.png image.png

    这两句代码就实现了上图中的继承关系。但是__proto__不是一个标准属性,因此不能直接写 Man.prototype.__proto__ = Human.prototype,我们可以通过 new 来间接操作__proto__

    new内部做的几件事

    但是 Human 中有this.name = name

     function Human(name){
         this.name = name
     }
    

    直接写为Man.prototype = new Human()的话,由于 new 内的第④个步骤,会执行Human.call(),会出现我们不需要的结果。

    你说把this.name = name删掉就可以了呀,但这样又会破坏原本的父类Human中的结构,于是我们就陷入了想删又不能删的境地。

    解决方法:

    我们可以用下面三句代码来代替

     var f = function(){} // 声明一个空函数f
     f.prototype = Human.prototype // 让这个空函数f的原型指向Human的原型
     Man.prototype = new f() // Man.prototype.__proto__ = f.prototype
    

    这三句代码的作用就是让 Man.prototype.__proto = Human.prototype,且解决了上面的问题

    于是,最终完整版代码如下

     function Human(name){
         this.name = name
     }
     Human.prototype.run = function(){
         console.log("我叫"+this.name+",我在跑")
         return undefined
     }
     function Man(name){
    // 这里的this指向Man实例,将Man实例和name作为参数传入构造函数Human中
         Human.call(this, name) 
         this.gender = '男'
     }
    
    /*Man.prototype.__proto__ = Human.prototype*/
     var f = function(){}
     f.prototype = Human.prototype
     Man.prototype = new f()
    
     Man.prototype.fight = function(){
         console.log('糊你熊脸')
     }
    
    

    ES6实现继承的写法

    对比ES5的写法,ES6的写法就很容易理解了

     class Human{ 
         constructor(name){ // 自身属性写到constructor中
             this.name = name
         }
         run(){ // 原型上的属性就直接写在Human这个类中
             console.log("我叫"+this.name+",我在跑")
             return undefined
         }
     }
    // Man extends Human 等价于 Man.prototype.__proto = Human.prototype,也相当于上面的三句代码
     class Man extends Human{ 
         constructor(name){ 
             super(name) // 相当于Human.call(this, name) 
             this.gender = '男'
         }
         fight(){
             console.log('糊你熊脸')
         }
     }
    

    那如果想在原型上声明一个非函数如何做到呢?

    ES5的写法:

     function Human(name){
         this.name = name
     }
     Human.prototype.种族 = '人类'
     Human.prototype.run = function(){
         console.log("我叫"+this.name+",我在跑")
         return undefined
     }
    

    ES6的写法:

     class Human{ 
         constructor(name){ // 自身属性写到constructor中
             this.name = name
         }
         get 种族(){
             return '人类'
         }
         run(){ // 原型上的属性就直接写在这个类中
             console.log("我叫"+this.name+",我在跑")
             return undefined
         }
     }
    

    相关文章

      网友评论

        本文标题:浅谈 JS 中继承的写法

        本文链接:https://www.haomeiwen.com/subject/alzopctx.html