zoukankan      html  css  js  c++  java
  • Javascript中,实现类与继承的方法和优缺点分析

    Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承

    第一种方法:利用Javascript中的原型链

      1 //首先定义一个父类
      2 
      3 function Animal(name,age){
      4     //定义父类的属性
      5     this.name = name || "Animal";
      6     this.age    =  age ;
      7     //定义父类的方法
      8     this.sleep = function(){
      9         console.log("这只"+this.name+"正在睡觉!");
     10     };
     11     this.showAge = function(){
     12         console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
     13     }
     14 };
     15 
     16 //为父类添加原型方法
     17 
     18 Animal.prototype.eat =function(food){
     19     console.log("这只"+this.name+"正在吃"+food+"!")
     20 }
     21 
     22 Animal.prototype.weight = 10;
     23 
     24 Animal.prototype.bark = function(){
     25     console.log("bark");
     26 }
     27 
     28 //Javascript实现继承的方法一:
     29 
     30 //原型链法    核心:将父类的实例作为子类的原型
     31 
     32 function Cat(){
     33 
     34 };
     35 
     36 Cat.prototype = new Animal();
     37 
     38 Cat.prototype.name = "猫";
     39 
     40 Cat.prototype.age = 3;
     41 
     42 Cat.prototype.bark = function(){
     43     console.log("喵喵"); 
     44 }
     45 
     46 //测试上面的例子
     47 
     48 var  cat = new Cat();
     49 
     50 console.log(cat.name);                                //输出猫
     51 
     52 console.log(cat.age);                                   //输出 3
     53 
     54 console.log(cat.weight);                              // 输出10
     55 
     56 cat.sleep();                                                  //输出 这只猫正在睡觉!
     57 
     58 cat.showAge();                                            //输出 这只猫的年龄是3岁!
     59  
     60 cat.eat("鱼");                                               //输出 这只猫正在吃鱼!
     61 
     62 cat.bark();                                                   //输出喵喵
     63 
     64 console.log(cat instanceof Animal);            //输出 true
     65 
     66 console.log(cat instanceof  Cat);                 //输出 true
     67 
     68 
     69 var Dog = new Function;                  // 为什么这样写也可以呢? 例子最后将做解释
     70 
     71 Dog.prototype = new Animal();
     72 
     73 Dog.prototype.name = "狗";
     74 
     75 Dog.prototype.age = 4;
     76 
     77 Dog.prototype.bark = function(){
     78    console.log("汪汪");
     79 }
     80 
     81 var dog = new Dog();
     82 
     83 console.log(dog.name);                               //输出 狗
     84 
     85 console.log(dog.age);                                  //输出 4
     86 
     87 console.log(dog.weight);                             //输出 10
     88 
     89 dog.sleep();                                                 //输出 这只狗正在睡觉!
     90 
     91 dog.eat("骨头");                                           //输出 这只狗正在吃骨头
     92 
     93 dog.bark();                                                  //输出 汪汪
     94 
     95 console.log(dog instanceof Dog);                //输出true
     96 
     97 console.log(dog instanceof Animal);            //输出true
     98  
     99 console.log(Animal.constructor);                 //输出 Function
    100 
    101 console.log(Cat.constructor);                       //输出 Function 
    102 
    103 console.log(Dog.constructor);                      //输出 Function 
    104 
    105 console.log(cat.constructor);                        //输出 function Animal(){...}
    106 
    107 console.log(dog.constructor);                      //输出 function Animal(){...}
    108 
    109 /*有上面四行的输出结果可以看书,Animal 父类,以及Cat  和  Dog 子类,都是由Function 创建出来的构造函数,
    110 而 cat  和  dog   是由Animal 父类构建出来的子类 */

    原型链法实现继承的特点分析

       优点:           1.是非常纯粹的继承关系,实例是子类的实例,也是父类的实例,     2.父类新增原型属性和原型方法,子类都可以访问到     3.简单方便,易于实现

        缺点 :           1.想要为子类添加原型属性和原型方法,则必须在new Animal() 语句之后执行     2.无法实现多继承     3.来自原型对象的引用属性是所有实例共享的(由Cat 和 Dog 都可以使用weight 属性 和 eat 方法可以看出)     4.创建子类实例时,无法向父类构造函数传参

    第二种方法:  构造函数法

    //首先定义一个父类
    
    function Animal(name,age){
        //定义父类的属性
        this.name = name || "Animal";
        this.age    =  age ;
        //定义父类的方法
        this.sleep = function(){
            console.log("这只"+this.name+"正在睡觉!");
        };
        this.showAge = function(){
            console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
        }
    };
    
    //为父类添加原型方法
    
    Animal.prototype.eat =function(food){
        console.log("这只"+this.name+"正在吃"+food+"!")
    }
    
    Animal.prototype.weight = 10;
    
    Animal.prototype.bark = function(){
        console.log("bark");
    }
    
    
    //Javascript 实现继承的方法二  :
    
    //构造函数法    核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类,但父类的原型属性和原型方法在子类中不能提现
    
    function Cat(name,age){
        Animal.call(this);                          //使用call方法继承父类的属性和方法
        this.name = name || "猫";            //使用子类自己的属性覆盖从父类继承来的属性
        this.age = age;                           //使用子类自己的属性覆盖从父类继承来的属性
        this.bark = function(){                //定义子类自己的方法
            console.log("喵喵");
        }
    };
    
    //测试
    
    var  cat = new Cat("猫",4);             //新创建一个子类实例化对象,并传参
    
    console.log(cat.name);                 // 输出 猫
    
    console.log(cat.age);                    //输出 4
    
    
    console.log(cat.weight);                //这一句会报undefined,因为父类的原型属性在子类中无法使用
    
    cat.sleep();                                   // 输出 这只猫正在睡觉
    
    cat.bark();                                    //输出喵喵
    
    //cat.eat("鱼");                              //这一句会报错,因为父类的原型方法在这里不能使用
    
    cat.showAge();                             //输出         
    
    console.log(cat instanceof Animal); // false
    
    console.log(cat instanceof Cat); // true
    
    //上面这两句可以看书,cat 并不属于Animal 父类的实例对象,而只是Cat 子类的实例对象
    
    
    //总结
    
    /*构造函数法实现继承的方法的特点分析
    
       优点:
              1.解决了原型链法中,子类实例对象会共享父类引用属性的问题;
              2.创建子类实例对象时,可以向父类传递参数
              3.可以实现多继承(通过call多个父类对象)
    
        缺点:
               1.实例对象并不是父类的实例对象,而只是子类的实例对象,(举例(小花猫属于猫类,却不属于动物类),这点很不好)
               2.只能继承父类的实例属性和实例方法,不能继承父类的原型属性和原型方法
               3.无法实现函数的复用,每个子类都有父类实例函数的副本,影响性能

    构造函数法实现继承的优缺点分析:

    优点:           1.解决了原型链法中,子类实例对象会共享父类引用属性的问题;     2.创建子类实例对象时,可以向父类传递参数     3.可以实现多继承(通过call多个父类对象)

     缺点:         1.实例对象并不是父类的实例对象,而只是子类的实例对象,(举例(小花猫属于猫类,却不属于动物类),这点很不好)      2.只能继承父类的实例属性和实例方法,不能继承父类的原型属性和原型方法      3.无法实现函数的复用,每个子类都有父类实例函数的副本,影响性能

    第三种方法:实例继承法

    //首先定义一个父类
    
    function Animal(name,age){
        //定义父类的属性
        this.name = name || "Animal";
        this.age    =  age ;
        //定义父类的方法
        this.sleep = function(){
            console.log("这只"+this.name+"正在睡觉!");
        };
        this.showAge = function(){
            console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
        }
    };
    
    //为父类添加原型方法
    
    Animal.prototype.eat =function(food){
        console.log("这只"+this.name+"正在吃"+food+"!")
    }
    
    Animal.prototype.weight = 10;
    
    Animal.prototype.bark = function(){
        console.log("bark");
    }
    
    //Javascript 实现继承的方法二  :
    
    //实例继承     核心:为父类实例添加新特性,作为子类实例返回
    
    function Cat(name,age){
        var obj = new Animal();     //   创建一个父类的实例对象obj
        //这里为obg添加了一个不可枚举属性 sex
        Object.defineProperty(obj, "sex", {
            value: "female",
            enumerable: false
    
        });
        obj.name = "猫";               // 为实例对象添加 属性  
        obj.age = 3;                      // 为实例对象添加 属性  
        obj.bark = function(){        // 为实例对象添加方法 
            console.log("喵喵");
        }
        return obj;                        // 将这个实例对象作为返回值返回
    };
    
    //测试代码
    
    var  cat = new Cat();
    
    console.log(cat.name);                            //输出 猫
    
    console.log(cat.age);                               //输出 3
    
    console.log(cat.weight);                          // 输出 10
    
    console.log(cat.sex);                               //输出female
    
    cat.sleep();                                              // 输出 这只猫正在睡觉
    
    cat.eat("鱼");                                           // 输出 这只猫正在吃鱼
    
    cat.bark();                                                //输出 喵喵
    
    console.log(cat instanceof Cat);               //输出false    
    
    //instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
    //instanceof 运算符可以用来判断一个对象是否属于某种对象类型
    //instanceof 运算符更好的用途是可以判断一个实例是否属于它的父类
    
    console.log(cat instanceof Animal);          //输出 true
    
    //上面这两句可以看书,cat 并不属于Cat的实例对象,而只是Animal父类的实例对象
    
    //总结 
    
    /*实例继承法的特点分析
    
        优点:
               1.不限制调用方式
    
        确定:
               1.实例是父类的实例,并不是子类的实例(这里好像违反了继承的理念,就好像小花猫属于动物,却不属于猫类一样)
               2.不支持多继承

     优点:         1.不限制调用方式

        确定:            1.实例是父类的实例,并不是子类的实例(这里好像违反了继承的理念,就好像小花猫属于动物,却不属于猫类一样)      2.不支持多继承

    第四种法法:组合继承法

    /首先定义一个父类
    
    function Animal(name,age){
        //定义父类的属性
        this.name = name || "Animal";
        this.age    =  age ;
        //定义父类的方法
        this.sleep = function(){
            console.log("这只"+this.name+"正在睡觉!");
        };
        this.showAge = function(){
            console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
        }
    };
    
    //为父类添加原型方法
    
    Animal.prototype.eat =function(food){
        console.log("这只"+this.name+"正在吃"+food+"!")
    }
    
    Animal.prototype.weight = 10;
    
    Animal.prototype.bark = function(){
        console.log("bark");
    }
    
    
    //Javascript 实现继承的方法五  :
    
    //组合继承法     核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
    
    function Cat(name,age){
        Animal.call(this);
        this.name = name;
        this.age = age;
        this.bark = function(){
            console.log("喵喵");
        }
    };
    
    Cat.prototype = new Animal();
    
    //测试代码
    
    var  cat  =  new Cat("猫",3);
    
    console.log(cat.name);                                   //
    
    console.log(cat.age);                                     // 3
    
    console.log(cat.weight);                                // 10
    
    cat.showAge();                                             // 这只猫的年龄是3岁
    
    cat.eat("鱼");                                                // 这只猫正在吃鱼
    
    cat.sleep();                                                  // 这只猫正在睡觉
    
    cat.bark();                                                   // 喵喵
    
    console.log(cat instanceof Animal);             // true
    
    console.log(cat instanceof Cat);                   // true
    
    //从上面两行的输出结果来看,cat  是 父类 Animal 的 实例 ,也是子类Cat  的 实例

    组合继承法实现继承的特点分析

        优点:             1.弥补了构造函数法的缺陷,可以继承实例属性和方法,也可以继承原型属性和方法    2.既是子类的实例,也是父类的实例(比较符合继承的理念)    3.不存在引用属性共享问题    4.子类的实例对象可传参    5.函数可复用  缺点:          1.在生成子类实例对象的过程中,调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

    结论 :  一般情况下,推荐使用这种方式的继承,缺点是多消耗一点内存 

    第五种方法:寄生组合继承法

    //第六种,寄生组合继承法实现继承
    
    //首先定义一个父类
    
    function Animal(name,age){
        //定义父类的属性
        this.name = name || "Animal";
        this.age    =  age ;
        //定义父类的方法
        this.sleep = function(){
            console.log("这只"+this.name+"正在睡觉!");
        };
        this.showAge = function(){
            console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
        }
    };
    
    //为父类添加原型方法
    
    Animal.prototype.eat =function(food){
        console.log("这只"+this.name+"正在吃"+food+"!")
    }
    
    Animal.prototype.weight = 10;
    
    Animal.prototype.bark = function(){
        console.log("bark");
    }
    
    
    //Javascript 实现继承的方法六  :
    
    //寄生组合继承   通过寄生方式,砍掉父类的实例属性,
    //这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
    
    function Cat(name,age){
        Animal.call(this);
        this.name = name;
        this.age = age ;
        this.bark = function(){
            console.log("喵喵");
        }
    };
    
    //通过一个立即执行函数将父类的实例作为子类的原型
    (function(){
        //创建一个没有实例方法的类
        var superClass = new Function;  //  这里也可以写成,var  sup = function(){}; 总之就是定义一个空构造函数
        superClass.prototype = Animal.prototype;
        //将实例作为子类的原型
        Cat.prototype = new superClass();
    })();
    
    //测试代码
    
    var cat = new Cat("猫",3);
    
    console.log(cat.name);                                    //
    
    console.log(cat.age);                                       // 3
    
    console.log(cat.weight);                                  // 10
    
    cat.showAge();                                               //这只猫的年龄是3岁!
     
    cat.eat("鱼");                                                  //这只猫正在吃鱼!
    
    cat.sleep();                                                     //这只猫正在睡觉!
    
    cat.bark();                                                      //喵喵
    
    console.log(cat instanceof Animal);               // true
    
    console.log(cat instanceof Cat);                    //true
    
    //上面两行可以看出,cat 是 子类 Cat  的实例对象, 也是 父类 Animal 的 实例对象

    寄生组合继承法的特点分析

        优点 :          1.集中了几种方法的优点,堪称完美

        缺点 :           1.实现比较复杂

    结论:  在实际项目和工程中,推荐使用这种方法

     

  • 相关阅读:
    FreeMarker常用语法学习
    Oracle如何实现创建数据库、备份数据库及数据导出导入的一条龙操作-------sql方式
    Oracle Partition 分区详细总结
    oracle 当中,(+)是什么意思
    SQL中EXISTS的用法
    JS return false 与 return true
    Merge into语句用法及其效率问题
    几种设置表单元素中文本输入框不可编辑的方法
    Oracle存储过程基本语法
    UNIX网络编程——Socket粘包问题
  • 原文地址:https://www.cnblogs.com/liquanjiang/p/8681813.html
Copyright © 2011-2022 走看看