js继承——详解继承的几种方法

本文深入探讨JavaScript中的五种继承模式:类式继承、构造函数继承、组合继承、原型继承及寄生组合继承,剖析每种模式的工作原理及其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    <h1>2.2传宗接代——继承</h1>
    <h3>2.2.1 子类的原型继承——类式继承</h3>
    <p>类式继承原理:类的原型对象的作用就是为类添加共有方法,但类不能直接访问这些属性和方法,必须通过prototype来访问。
        而我们实例化一个父类的时候,新创建的对象复制了父类的构造函数内的属性与方法并且将原型_proto_指向了父类的原型对象,这样就拥有了父类原型对象上的属性与方法,
        并且这个新创建的对象可直接访问到父类原型对象上的属性与方法。如果我们将这个新创建的对象赋值给子类的原型,那么之类的原型就可以访问到父类的原型属性和方法。</p>
   <p>另外,新创建的对象不仅可以访问父类原型上的属性和方法,同样也可以访问父类构造函数中的复制的方法和属性。将这个对象赋值给子类的原型,那么这个子类的原型可以访问父类原型上的方法和属性与父类构造函数中复制的属性和方法。</p>
   <p>PS:这种类式继承有两个缺点:1.由于子类通过prototype对父类实例化,继承了父类。所以说父类中的共有属性要是引用类型,就会在子类中被所有实例共用,因此一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响到其他子类;2.由于子类实现的继承是靠其原型prototype对父类的实例化实现的,因此在创建父类的时候,
   是无法向父类传递参数的,因此在实例化父类的时候也无法对父类构造函数内的属性进行初始化。</p>
   <h3>2.2.2 创建即继承——构造函数继承</h3>
  <script>
      //构造函数式继承
      //声明父类
      var SuperCLass = function( id ){
         //引用类型共有属性
         this.books = [ "javascript", "html", "css" ];
         this.id = id;
      }
      //声明父类的方法
      SuperCLass.prototype.showBooks = function(){
         console.log( this.books );
      };
     
      //声明子类
      var SubClass = function( id ){
           //继承父类
           SuperCLass.call( this, id );
      };
      
      var instance1 = new SubClass( 10 );
      var instance2 = new SubClass( 11 );
      instance1.books.push( "设计模式" );
      console.log( instance1.books );
      console.log( instance1.id );
      console.log( instance2.books );
      console.log( instance2.id );
  </script>
   <p>PS:SuperClass.call( this, id );这条语句是构造函数式继承的精华,由于call这个方法可以改变函数的作用环境,
                 因此子类中,对SuperClass调用这个方法就是将子类中的变量在父类中执行一遍,由于父类中是给this绑定属性,因此子类也就继承了父类中共有属性。
                由于这种类型的继承没有设计原型prototype,所以父类的原型方法自然不会被子类继承,而如果想被子类继承就必须要放在构造函数中,这样创建出来的每个实例都会单独
                拥有一份而不能共用,这样就违背了代码复用的原则。为了综合着两种模式的优点,后来就有了组合式继承。</p>
    <h3>2.2.3 将优点为我所用——组合继承</h3>
    <script>
       //组合式继承
       //声明父类
       var SuperClass = function( name ){
          this.name = name;
          this.books = [ "html", "css", "javascript" ];
       };
       //父类原型共有方法
       SuperClass.prototype.getName = function(){
          console.log( this.name );
       };
       //声明子类
       var SubClass = function( name, time ){
           //构造函数式继承父类name属性
           SuperClass.call( this, name );
           //子类中新增共有属性
           this.time = time;
       }  
       //类式继承   子类原型继承父类实例
        SubClass.prototype = new SuperClass();
        //子类原型方法
        SubClass.prototype.getTime = function(){
           console.log( this.time );
        };
        
    </script>
    <p>PS:前两种继承模式的特点:类式继承是通过子类的原型prototype对父类实例化来实现的,构造函数是继承是通过在子类的构造函数作用环境中执行一次父类的构造函数来实现的,
         所以只要在继承中同时做到这两点即可。</p>
     <p>在子类构造函数中执行父类构造函数,在子类原型上实例化父类就是组合模式,这样就融合了类式继承和构造函数继承的优点,并且过滤其缺点。</p>
     <p>缺点:我们在使用构造函数继承时执行了一遍父类的构造函数,而实现子类原型继承时又调用了一遍父类的构造函数。因此,父类构造函数调用了两遍,所以这还不是最完美的方式。</p>
     
<h3>2.2.4 洁净的继承者——原型式继承</h3>
     <script>
        //原型式继承
        var InheritObject = function( o ){
            //声明一个过渡函数对象
            function F(){};
            //过渡对象的原型继承父对象
            F.prototype = o;
            //返回过渡对象的一个实例,该实例的原型继承了父对象
            return new F();
        };
        //跟类式继承一样,父类对象中的值类型属性被复制,引用类型的属性被共用。
        //然而这种继承并不止这一种,在此基础上做了一些增强而推出一种寄生式继承
     </script>
     <h3>2.2.5 如虎添翼——寄生式继承</h3>
     <script>
         //寄生式继承
         //声明基对象
         var book = {
             name: "js book",
             alikeBook: [ "css book", "html book" ]
         };
         var createBook = function(){
            //通过原型继承方式创建新对象
            var o = new InheritObject( book );
            //拓展新对象
            o.getName = function(){
               console.log( this.name );
            };
            
            return o;
         };
         //其实寄生式继承就是对原型继承的第二次封装,并且在这第二次封装过程中对继承的对象进行了拓展,这样创建的对象不仅仅有父类中的属性和方法而且还添加新的属性和方法。
         //这种类型的继承果如其名,寄生大概指的就是像寄生虫一样寄托于某个对象内部生长。当然寄生式继承这种增强新创建对象的继承思想也是寄托于原型模式吧。
         //而这种思想的作用也是为了寄生组合式集成模式的实现。
     </script>
     <h3>2.2.6 终极继承者——寄生组合式继承</h3>
     <script>
        /**
          	 寄生式继承  继承原型
          	 传递参数 subClass 子类
          	 传递参数 superClass 父类 
        **/
       var inheritPrototype = function( SubClass, SuperClass ){
           //复制一份父类的原型副本保存在变量中
           var p = InheritObject( SuperClass.prototype );
           //修正因为重写子类原型导致子类的constructor属性被修改
           p.constructor = SubClass;
           //设置子类的原型
           SubClass.prototype = p;
        }
        //定义父类
        var SuperClass = function( name ){
           this.name = name;
           this.colors = [ "red", "blue", "green" ];
        };
        //定义父类的原型方法
        SuperClass.prototype.getName = function(){
           console.log( this.colors );
        };
        //定义子类
        var SubClass = function( name, time ){
           //构造函数式继承
          SuperClass.call( this, name );
          //子类新增属性
          this.time = time;
        }
        //寄生式继承父类原型
        inheritPrototype( SubClass, SuperClass );
        //子类新增原型方法
        SubClass.prototype.getName = function(){
          console.log( this.name );
        };
        
        //创建两个测试方法
        var instance1 = new SubClass( "xiexialing", 2016 );
        var instance2 = new SubClass( "xialing", 2017 );
        instance1.colors.push( "black" );
        console.log( instance1.colors );
        console.log( instance2.colors );
        instance1.getName();
        instance2.getName();
     </script>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值