最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript的几种继承方式

    正文概述 掘金(z0aiyx)   2020-12-06   419

    1.原型链继承

    原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。

    • 这里先简单介绍下原型

    js中每个对象都有一个__proto__属性,这个属性指向的就是该对象的原型。js中每个函数都有一个prototype属性,这个属性指向该函数作为构造函数调用时创建的实例的原型。原型对象上有一个constructor属性,指向创建该对象的构造函数,该属性不可枚举。

    var obj = {};
    obj.__proto__ === Object.prototype;   //true
    console.log(Object.prototype.constructor)  // ƒ Object
    

    当我们访问一个对象的属性或者方法时,如果找不到,则会通过原型向上寻找,若原型上也未找到,则会去原型的原型上面去找。比如我要调用obj.toString方法时,在自身并未找到toString方法,则会去原型上去寻找,即在Object.prototype上去寻找,找到后运行该方法。

    var obj = {};
    obj.toString();
    obj.__proto__.toString(); //obj.__proto__和Object.prototype指向的是一个对象,自然就能访问Object.prototype上的toString方法啦 
    

    注意:原型链的终点是null,使用bind方法返回的函数没有prototype属性。

    var obj = {};
    function fn(){};
    fn.bind(obj).prototype;  // undefined
    Object.prototype.__proto__; // null
    
    • 原型链接继承
    function Father(age){
        this.age = age;
        this.color = ['red','pink']
    }
    Father.prototype.sayHello = function(){
        console.log('hello')
    }   
    function Son(sex){
        this.sex = sex
    }
    console.log(Son.prototype.constructor) // ƒ Son
    Son.prototype = new Father(15) // 原型链继承关键
    var son = new Son('男')
    son.color.push('black')
    var son2 = new Son('女')
    son.sayHello() // hello
    son.sayHello === son2.sayHello //true
    console.log(son2.color) // ['red','pink','black']
    console.log(Son.prototype.constructor) // ƒ Father
    

    可以看到通过原型链实现继承,原型上引用类型的值会被所有实例共享。子类的constructor指向会发生改变,而且在创建子类实例时不可以向父类构造函数传递参数。可以手动把子类constructor属性指回其构造函数。

    //写法一
    Son.prototype.constructor = Son // 这种写法有点缺点,它会让constructor属性变的可以枚举。
    
    //写法二
    Object.defineProperty(Son.prototype,'constructor',{
        enumerable:false, // 设置不可枚举
        value:Son
    })
    

    2.构造函数继承

    原理:在子类构造函数中通过apply或者call调用父类构造函数来继承属性或方法。

    function Father(name){
        this.color = ['red']
        this.sayHello = function(){
            console.log('hello')
        }
    }
    Father.prototype.sayName = function(){
        console.log('zs')
    }
    function Son(num,name){
        Father.call(this,name) //实现继承的关键代码
        this.num = num
    }
    var son = new Son(10,'zs')
    var son2 = new Son(15,'ls')
    son.color.push('pink')
    console.log(son2.color) // ['red']
    son.sayName() //报错 son.sayName is not a function
    console.log(son.sayHello === son2.sayHello) //false
    

    可以看出通过构造函数实现继承,解决了原型链继承不能向父类传参以及引用类型值共享的问题。但这种继承方法却不能访问父类构造函数原型上的方法和属性,而且定义在父类构造函数中的方法也不能复用。

    3.组合式继承

    组合继承,有时候也叫伪经典继承,它是将原型链继承和构造函数继承结合到一起的一种继承模式。实现思路是通过原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

    function Father(name){
        this.color = ['red']
    }
    Father.prototype.sayName = function(){
        console.log('zs')
    }
    function Son(num,name){
        Father.call(this,name) //继承实例属性
        this.num = num
    }
    Son.prototype = new Father() //继承原型上属性
    Son.prototype.constructor = Son
    var son = new Son(10,'zs')
    var son2 = new Son(15,'ls')
    son.color.push('pink')
    console.log(son.color,son2.color) //['red','pink']   ['red']
    son.sayName() // zs
    

    组合式继承避免了原型链继承和构造函数继承的缺点,融合了它们的优点,成为JavaScript中常用的一种继承模式。

    4.寄生式继承

    寄生式继承与工厂模式类似,一般用来继承对象。即创建一个封装继承的函数,在函数内部复制一份该对象,对复制的对象进行处理,返回复制的对象。

    function createAnother(obj){
         var clone = Object.create(obj)
         clone.name = 'zs'
         clone.sayHello = function(){
             console.log('hello')
         }
         return clone
    }
    var obj = {age:15}
    var newObj = createAnother(obj) // 15
    console.log(newObj.name)  // zs
    newObj.sayHello() // hello
    

    5.寄生组合式继承

    前面说到过组合式继承是Javascript中最常用的继承模式,不过这种模式也有自己的不足,它会调用两次父类构造函数。第一次是在将子类原型指向父类实例的时候,第二次是在子类构造函数中调用的。

    function Father(name){
          this.name = name
      }
      function Son(num,name){
          Father.call(this,name) // 第二次调用
      }
      Son.prototype = new Father('ls') // 第一次调用
      var son = new Son(10,'zs')
      console.log(son)
    
    

    在第一次调用的时候,Son.prototype会继承name这个属性,第二次调用时,实例对象会继承name。当我们获取实例对象的name属性时因为实例对象上有该属性,所以是不会去原型上去寻找的,相当于实例对象上的name属性把原型上的name属性给屏蔽掉了,所以原型上的这个属性是多余的。 JavaScript的几种继承方式

    为了解决这个问题,就有了寄生组合式继承。主要思路就是创建一个函数完成原型链继承和constructor的指向问题,然后通过构造函数继承属性。

     // 复制一个父类的原型指向,将子类的原型指向复制的父类原型,达到不用调用父类构造函数就能继承其原型上的方法的效果。
     function inherit(Sup,Sub){
         var prototype = Object.create(Sup.prototype)
         Sub.prototype = prototype
         prototype.constructor = Sub
     }
     function Father(name){
         this.name = name
     }
     function Son(name){
        Father.call(this,name)
     }
     inherit(Father,Son)
     var son = new Son('zs')
     console.log(son)
    

    JavaScript的几种继承方式

    以上就是JavaScript中常用的几种继承方式啦。


    起源地下载网 » JavaScript的几种继承方式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元