• JS面向对象编程(二):构造函数的继承


    对象之间继承的 5 中方法.
                比如, 现在有一个"动物"对象的构造函数.
                function Animal(){
                    this.species = "动物";
                }
                还有一个"猫"对象构造函数
                function Cat(name,color){
                    this.name = name;
                    this.color = color;
                }
                怎样才能使猫继承动物呢?
                
                一.构造函数绑定
                    第一种方法,也是最简单的方法,使用call 或 apply 方法, 将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:


                    function Cat(name,color){
                        Animal.apply(this, arguments);
                        this.name = name;
                        this.color = color;
                    }
                    var cat1 = new Cat("大毛","黄色");
                    alert(cat1.species);//猫科动物

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="UTF-8">
     5         <title>0.2-1 obj</title>
     6     </head>
     7     <body>
     8         <script>
     9             //父构造函数
    10             function Animal(){
    11                 this.species = "猫科动物"
    12             }
    13             
    14             //子构造函数
    15             function Cat(name,color){
    16                 Animal.apply(this,arguments);
    17                 this.name = name;
    18                 this.color = color;
    19             }
    20             
    21             //构造实例
    22             var cat1 = new Cat("大毛","黑色");
    23             alert(cat1.species);
    24         </script>
    25     </body>
    26 </html>

                   
                二.Prototype模式
                    第二种方法更常见,使用 Prototype属性.
                    如果用"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了.
                    
                    Cat.prototype = new Animal();
                    它相当于完全删除了prototype对象原先的值, 然后赋予一个新值.但是第二行又是什么意思呢?
                    Cat.prototype.constructor = Cat;
                    原来, 任何一个prototype对象都有一个constructor属性,指向它的构造函数.如果没有"Cat.prototype=new Animal();"这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后,Cat.prototype.constructor指向Animal.
                    alert(Cat.prototype.constructor == Animal);//true
                    
                    cat1使用构造函数Cat生成的,因此我们需要手动纠正,将Cat.prototype对象的contructor值改为Cat,不然就会导致继承链的紊乱.
                    
                    注: 这是编程中很重要的一点,编程时务必遵守.
                    
                    如果替换了prototype对象,
                    o.prototype = {};
                    那么, 下一步必然会成为新的 prototype对象加上constructor属性,并将这个属性指回原来的构造函数.
                    o.prototype.constructor = o;

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="UTF-8">
     5         <title>0.2-2 </title>
     6     </head>
     7     <body>
     8         <script>
     9             function Animal(){
    10                 this.species = "动物";
    11             }
    12             
    13             function Cat(name,color){
    14                 this.name = name;
    15                 this.color = color;
    16             }
    17             Cat.prototype = new Animal();
    18             alert(Cat.prototype.constructor);//Animal
    19             Cat.prototype.constructor = Cat;
    20             alert(Cat.prototype.constructor);//Cat
    21             
    22             var cat1 = new Cat("大毛","黄色");
    23             alert(cat1.species);//动物
    24             
    25         </script>
    26     </body>
    27 </html>


                    
                三.直接继承prototype
                    第三种方法是对第二种方法的改进. 由于Animal对象中, 不变的属性都可以直接写入 Animal.prototype. 所以,我们也可以让 Cat()跳过Aniaml(),直接继承Animal.prototype.
                    
                    现在, 我们先将Animal对象改写:
                    function Animal(){}
                    Animal.prototype.species = "动物";
                    然后,将 Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承.
                    
                    Cat.prototype = Animal.prototype;
                    Cat.prototype.constructor = Cat;
                    var cat1 = new Cat("大毛","黄色");
                    alert(cat1.species);//动物


                    与前一种方法相比, 这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存. 缺点是Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype.
                    所以,上面这一段代码其实是有问题的.请看第二行
                    Cat.prototype.constructor = Cat;
                    这一句话实际上把Aniaml.prototype对象的constructor属性也改掉了!
                    alert(Animal.prototype.constructor);//Cat
                    
                四.利用空对象作为中介
                    由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介.


                    var F = function(){};
                       F.prototype = Animal.prototype;
                       Cat.prototype = new F();
                       Cat.prototype.constructor = Cat;
                    
                    F是空对象,所以几乎不占内存.这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象.
                    alert(Animal.prototype.constructor);//Animal
                    
                    
                    我们将上边的方法,封装成一个函数,便于使用.
                    function extend(Child,Parent){
                          var F = function(){};
                          F.prototype = Parent.prototype;
                          Child.prototype = new F();
                          Child.prototype.constructor = Child;
                          Child.uber = Parent.prototype;
                     }


                  //使用方法如下:
                 extend(Cat,Animal);
                    var cat1 = new Cat("大毛","黄色");
                    alert(cat1.species);//动物
                    这个extend函数,就是YUI库如何实现继承的方法.
                    
                    另外,说明一点,函数体最后一行
                    Child.uber = Parent.prototype;
                    意思是为子对象设一个uber属性, 这个属性直接指向父对象的prototype属性.这等于在子对象上打开一条通道,可以直接调用父对象的方法.这一行放在这里,只是为了实现继承的完备性,纯属备用性质.
                    
                五.拷贝继承
                    上面采用prototype对象,实现继承.我们也可以换一种思路,纯粹采用"拷贝"方法实现继承.简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?
                    
                    首先,还是把Animal的所有不变属性, 都放到它的prototype对象上.
                    function Animal(){};
                     Animal.prototype.species = "动物";
                    然后,再写一个函数,实现属性拷贝的目的.
                    function extend2(Child, Parent){
                          var p = Parent.prototype;
                          var c = Child.prototype;
                          for(var i in p){
                              c[i] = p[i];
                          }
                          c.uber = p;
                    }
                    这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象.
                    
                    使用的时候,这样写:
                    extent2(Cat,Animal);
                     var cat1 = new Cat("大毛","黄色");
                     alert(cat1.species);//动物

    原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

  • 相关阅读:
    【Unity3D】使用MD5值,确保本地Sqlite数据库内容没有被篡改
    《Unity3D》通过对象池模式,管理场景中的元素
    NGUI制作 《九宫格》 图片
    NGUI混合FingerGesture《卷二》分离触摸事件
    js的各种获取大小
    sass基础
    js面向对象开发基础
    正则表达式(进阶篇)
    正则表达式(基础篇)
    jquery源码学习(三)—— jquery.prototype主要属性和方法
  • 原文地址:https://www.cnblogs.com/helena000/p/6501216.html
Copyright © 2020-2023  润新知