• JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)


    JavaScript继承的6种方法

    1,原型链继承
    
    2,借用构造函数继承
    
    3,组合继承(原型+借用构造)
    
    4,原型式继承
    
    5,寄生式继承
    
    6,寄生组合式继承

    1.原型链继承.

    <script type="text/javascript">
        function Person(name,sex)
        {
            this.name=name;
            this.sex=sex;
            this.friends=['李四'];
            this.getName=function(){
                alert(this.name);
            }
        }
       Person.prototype.id=1;
    
        function Boy(age)
        {
            this.age=age;
            this.getAge=function(){
                alert(this.age);
            }
    
        }
        //继承
        Boy.prototype=new Person("张三","男");
    
    
        var boy=new Boy(16);
       
        alert(boy.name);              //张三
        boy.getAge();               //16
        alert(boy.id);                 //1
    
    
        //属性共享问题
        console.log(boy.friends);            //李四
    
        var boy2=new Boy(17);
        boy2.friends.push('王五');  //修改boy2的friends属性的同时也影响了boy的属性
    
        console.log(boy.friends);            //李四 王五
    
        //验证能否使用instanceof 和 isPrototypeof
        console.log(boy instanceof Person);                 //true
        console.log(Person.prototype.isPrototypeOf(boy));   //true
    </script>

    特点:既继承了父类的模板,又继承了父类的原型对象。

    缺点:只能在父类设置一些参数,子类不能灵活传参,不符合面向对象的思想,包含引用类型值的属性始终都会共享相应的值。

     

    2.借用构造函数继承

    <script type="text/javascript">
          //父类
        function Person(name,sex)
        {
            this.name=name;
            this.sex=sex;
            this.friends=['李四'];
        }
        Person.prototype.id=1;
        //子类
        function Boy(name,sex,age)
        {
    
            //借用
            Person.call(this,name,age);
    
            this.age=age;
            this.getAge=function(){
                alert(this.age);
            }
    
        }
    
    
        var boy=new Boy("张三","男",16);
        alert(boy.name);  //张三
    
        boy.getAge();        //16
    
        alert(boy.id);  //undefined  没有继承父类的原型对象
    
    
        //属性共享问题 ————不会有共享
      
    
        //验证能否使用instanceof 和 isPrototypeof
        console.log(boy instanceof Person);                 //false
        console.log(Person.prototype.isPrototypeOf(boy));   //false
    </script>

    特点:只继承了父类的模板,不继承父类的原型对象。

    缺点:方法都在构造函数中定义,不能做到函数复用。

    3.组合继承(原型+借用构造)最常用的继承模式

    <script type="text/javascript">
         //父类
        function Person(name,sex)
        {
            this.name=name;
            this.sex=sex;
            
        }
        Person.prototype.id=1;
        //子类
        function Boy(name,sex,age)
        {
    
            //借用构造函数  继承父类的模板
            Person.call(this,name,age);
    
            this.age=age;
            this.getAge=function(){
                alert(this.age);
            }
    
        }
        
        //不传递参数,继承父类的模板,继承父类的原型对象 id 
        Boy.prototype=new Person();
    
        var boy=new Boy("张三","男",16);
        alert(boy.name);  //张三
    
        boy.getAge();        //16
    
        alert(boy.id);  //1
    
    
        //属性共享问题 ————除了父类的原型对象,不会有共享
      
    
        //验证能否使用instanceof 和 isPrototypeof
        console.log(boy instanceof Person);                 //true
        console.log(Person.prototype.isPrototypeOf(boy));   //true
    </script>

    特点:既继承了父类的模板,又继承了父类的原型对象。

    缺点:做了3件事,继承了父类两次模板,继承了一次原型对象

    原型式继承解决了这个问题

    4.原型式继承

    <script type="text/javascript">
       var person={
        name:'张三',
        sex:'男',
        friends:['李四']
        }
    
        function object(obj)
        {
            function F(){}   //创建一个空的构造函数
            F.prototype=obj;  //将传入的对象作为这个构造函数的原型
            return new F();   //返回一个新实例  对传入的对象进行了一次浅复制
        }
    
        var boy=object(person);
        //ECMAScript 5 新增了Object.create()方法 与本例 object 方法行为相同
        //可改为 Object.create(person);
    
        alert(boy.name);  //张三
    
        //但是原型式同样存在属性共享的问题
        //例如:
    
        var girl=object(person);
        girl.friends.push('王五');
    
        alert(boy.friends); //李四 王五
        alert(girl.friends);//李四 王五
    
        //修改girl中的friends属性  boy 也会受到影响
      
    
           //无法使用 instanceof 和 isPrototypeof
       
    </script>

    创造的目的是基于已有的对象创建新的对象,同时还不必因此创建自定义类型。

    包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。

     

    5.寄生式继承

    <script type="text/javascript">
        function object(obj)
        {
            function F(){}   //创建一个空的构造函数
            F.prototype=obj;  //将传入的对象作为这个构造函数的原型
            return new F();   //返回一个新实例  对传入的对象进行了一次浅复制
        }
    
        function Person(person)
        {
            var clone=object(person);
            clone.getSex=function(){
                alert(this.sex);
            }
            return clone;
        }
        var person={
            name:'张三',
            sex:'男',
            friends:['李四']
        }
        var boy=Person(person);
        boy.getSex();         //
    
    
    
        //属性共享问题————因为传入同一个实例,所以存在共享问题
          var boy2=Person(person);
          boy2.friends.push('王五');
        
        alert(boy.friends);     //李四  王五
    
        
        //验证能否使用instanceof 和 isPrototypeof
        console.log(boy instanceof Person);                 //false
        console.log(Person.prototype.isPrototypeOf(boy));   //false
    </script>

    与构造函数模式类似,不能做到函数复用会降低效率。

    6.寄生组合式继承

    <script type="text/javascript">
        
        function object(o)
        {
            function F(){}
            console.log(o);
            F.prototype=o;
            return new F();
    
        }
        function extend(subType,superType)
        {
            var prototype=object(superType.prototype);  //创建父类的一个副本
            prototype.constructor=subType;                //为创建的副本添加失去默认的构造函数
            subType.prototype=prototype;                //将新创建的对象赋值给子类的原型
        }
        function Person(name)
        {
            this.name=name;
            this.friends=['李四'];
        }
        function Boy(name,sex)
        {
            Person.call(this,name);             //借用构造函数  继承父类的模板
            this.sex=sex;
        }
    
        extend(Boy,Person);  //继承
    
        var boy=new Boy('张三','男');
    
        alert(boy.name);     //张三
    
    
    
        //属性共享问题————不会存在共享问题
          var boy2=new Boy('张三','男');
          boy2.friends.push('王五');
        
        alert(boy.friends);     //李四
    
    
        //验证能否使用instanceof 和 isPrototypeof
        console.log(boy instanceof Person);                 //false
        console.log(Person.prototype.isPrototypeOf(boy));   //false
    </script>

    寄生式组合继承解决了组合继承会调用两次父类构造函数,子类最终会包含父类的全部实例属性,父类的属性不是必须的,子类的属性会覆盖父类的属性。

    寄生式组合继承只调用一次父类构造函数,原型链能保持不变,因此还能够正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生组合继承,是实现基于类型继承的最有效的方式。

  • 相关阅读:
    五大P2P平台费用一览
    警惕P2B模式
    仿照jquery封装一个自己的js库
    怎样给div增加resize事件
    美化浏览器滚动条效果
    手机端触屏手指滑动方向及拖动层
    JS中原型链中的prototype与_proto_的个人理解与详细总结(**************************************************************)
    JavaScript this用法总结(**************************************)
    js中call、apply、bind那些事2
    深刻理解JavaScript---闭包
  • 原文地址:https://www.cnblogs.com/herozhou/p/6870224.html
Copyright © 2020-2023  润新知