JS Class construct and extend

来源:互联网 发布:上海市政府数据服务网 编辑:程序博客网 时间:2024/05/16 14:16
最近有点迷上javascript, 潜下心来, 仔细理了下JS的对象构造

关于对象构造, 大致有以下几种pattern

1. factory
工厂模式, 很传统的啦, 主要就是在构造函数里临时创建一个Object, 然后把所有资源都赋予这个实例, 最后返回这个实例的引用, 创建对象时不需要new, 工厂模式嘛,
缺点是, 因为最后的引用不是原来的Class, 所以Class的prototype完全废了

2. constructor
构造模式, 很Java的风格, 构造器里, 把所有资源赋给this, 然后返回这个this的引用
缺点是, 里面的方法也随着数据一样, 每new一个实例, 就重复一份
比较纠结的是, 一定要用new, 不然的话, 里面的this指针不定指哪去了,
一般指向最外层的window对象
另外, js构造器的特色, 在构造函数结束时, 会隐式执行代码
return this;

3. factory/constructor mix
在constructor的基础上, 把里面的方法放到外面, 利用prototype属性, 让每个实例都能访问,
注意不是静态函数那种, 想想如果是静态函数, 就没办法直接访问实例里的数据了


关于继承, 没想到啊, 我居然会琢磨起JS的继承来了, 想当年, 信誓旦旦地认为自己不会用JS的对象继承, 以免搞得太复杂了...

JS里确实没有继承的语法, 所以, 我们必须人为地虚拟它
主要的继承手段有
1, 通过指针欺骗
里子类里, 如父类为ClassA
this.parent=Class;  //指针指向父类构造函数
this.parent();      //执行父类构造函数, 这里, 父类的构造器里的this会指向子类, 所有资源的引用就都被骗到子类里了, 嘿嘿
delete this.parent; //销毁痕迹, 自欺欺人...

想不到, javascript看见大家都这样做之后, 居然也凑上一脚, 特别提供了2个函数方便大家作案
call(this, param1, param2, param3, ...)
apply(this, Array)
2个函数其实一样, 就是后面的参数不同而已, apply里用Array把第2个以后的参数全部打包到数组里了, 有这2个函数, 就可以取代上面的那3行代码了, 作案手法更专业了...
但可能父类的prototype里的方法都丢失了

2, 通过原型
原型链是JS里很值得钻研的东西, 这里只说有关继承的,
上面的方法, 虽然把构造器里的所有资源骗到手, 但prototype里的方法却损失了,
所以有了这个补充
父类A, 子类B
B.prototype=A.prototype  //这样写很好理解, 指针对上指针了
or
B.prototype=new A();  //为什么new个实例也可以, 因为返回的是this, prototype的方法就是直接由实例调用的, 而不是静态类调用

B.prototype=A; //这是错误的, 这样指针指向父类的构造函数了
这样, 父类的方法也就入手了

注意子类的方法要在这个prototype"继承"之后再写


以下是测试代码
1.<html>  2.  <head>  3.    <title></title>  4.    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  5.    <style type="text/css">  6.        form input[type="button"] {width: 150px}  7.    </style>  8.    <script type="text/javascript">  9.    //declare Class in JavaScript  10.      11.    /* 12.     * factory pattern<br /> 13.     * point1, the duplication when new Car() every time<br /> 14.     * point2, new Car() and Car(), it's same result<br /> 15.     * point3, prototype is for Car, but the finger have been change in constructor,<br /> 16.     * so the method of prototype are be lost<br /> 17.     */  18.    function demoFactory(){  19.        //function Car, the same indicate, the comment isn't support by NetBean 6.8  20.        //var Car=function(color, brand, engineLv){}, recommandation, for comment view  21.  22.        /** 23.         * function description 24.         * @param color 25.         * @param brand 26.         * @param enginelv 27.         * @return  28.         */  29.        var Car=function(color, brand, engineLv){  30.            var e=new Object;  31.            e.color=color;  32.            e.brand=brand;  33.            e.engineLv=engineLv;  34.            e.getDetail=function(){alert(e.color+", "+e.brand+", "+e.engineLv);};   //*1  35.            return e;  36.        };  37.        Car.show=function(){alert("zoo zoo")};      //it's ok  38.        Car.prototype.show2=function(){alert("Car prototype")}; //it's wrong *3  39.        var car1=new Car('black', 'Mazda5', '2.0L');    //*2  40.        var car2=Car('black', 'Mazda5', '2.0L');  41.        try{  42.            car1.getDetail();  43.            car2.getDetail();  44.            Car.show();  45.            car2.show2();  46.        }catch(err){  47.            alert(err);  48.        }  49.    }  50.  51.    /**  52.     * constructor/prototype mix parttern, <u>recommendation in <b>ECMSscript</b></u><br />  53.     * point1, the "this" must be, else the color are belong "window", it mean window.color<br />  54.     * point2, same as point1, but the question of duplication still be<br />  55.     * point3, the error that method of prototype is solved<br />  56.     */  57.    function demoConstructor(){  58.        var Car=function(color, brand, engineLv){  59.            this.color=color;       //*1  60.            this.brand=brand;  61.            this.engineLv=engineLv;  62.            this.getDetail=function(){alert(this.color+", "+this.brand+", "+this.engineLv);};   //*2  63.        };  64.        Car.prototype.show2=function(){alert("Car prototype")}; //it's ok, *3  65.        Car.show=function(){alert("zoo zoo")};      //it's ok  66.        var car1=new Car('black', 'Mazda5', '2.0L');  67.        var car2=new Car('silver', 'Mazda5', '2.0L');  68.        try{  69.            car1.getDetail();  70.            car2.getDetail();  71.            Car.show();  72.            car2.show2();  73.        }catch(err){  74.            alert(err);  75.        }  76.    }  77.  78.  79.    /**  80.     * constructor parttern<br />  81.     * point1, the "this" must be, else the color are belong "window", it mean window.color<br />  82.     * point2, declare the method to prototype method, the duplication question are solved<br />  83.     * point3, the error that method of prototype is solved<br />  84.     */  85.    function demoMix(){  86.        var Car=function(color, brand, engineLv){  87.            this.color=color;       //*1  88.            this.brand=brand;  89.            this.engineLv=engineLv;  90.        };  91.        Car.prototype.getDetail=function(){alert(this.color+", "+this.brand+", "+this.engineLv);};  //*2  92.        Car.show=function(){alert("zoo zoo")};      //it's ok  93.        Car.prototype.show2=function(){alert("Car prototype")}; //it's ok, *3  94.        var car1=new Car('black', 'Mazda5', '2.0L');  95.        var car2=new Car('silver', 'Mazda5', '2.0L');  96.        car1.getDetail();  97.        car2.getDetail();  98.        try{  99.            Car.show();  100.            car2.show2();  101.        }catch(err){  102.            alert(err);  103.        }  104.    }  105.  106.    /**  107.     * Extend demo: Object virtual<br />  108.     * the expend is not support in JavaScript<br />  109.     * so we must perform it throught by coding, and virtual the extend effect<br />  110.     * point1, the prototype finger to CarGas, not Car, so the prototype method error  111.     */  112.    function demoExtend1(){  113.        var Car=function(color, brand, engineLv){  114.            this.color=color;       //*1  115.            this.brand=brand;  116.            this.engineLv=engineLv;  117.            this.getDetail=function(){alert(this.color+", "+this.brand+", "+this.engineLv);};   //*2  118.        };  119.        Car.show=function(){alert("zoo zoo")};      //it's ok  120.        Car.prototype.show2=function(){alert("Car prototype")}; //it's ok, *3  121.  122.        var CarGas=function(color, brand, engineLv, gasNo){  123.            this.gasNo=gasNo;  124.            this.extend=Car;  125.            this.extend(color, brand, engineLv);  126.            delete this.extend;     //it's no mind, either it delete or not delete  127.        }  128.        var car=new CarGas("back", "Mazda5", "2.0L", "97");  129.        try {  130.            alert(car.gasNo);  131.            car.getDetail();  132.            Car.show();  133.            car.show2();    //*1  134.        } catch (err) {  135.            alert(err);  136.        }  137.    }  138.  139.    /**  140.     * Extend Demo: Object virtual with method <b>call()</b> and <b>apply()</b><br />  141.     * method <b>call</b> and <b>apply</b> is same except parameter<br />  142.     * call's parameter: 1, "this", 2, param, 3, param, 4, param, ...<br />  143.     * apply's parameter: 1, "this", 2, Array  144.     */  145.    function demoExtend2(){  146.        var Car=function(color, brand, engineLv){  147.            this.color=color;       //*1  148.            this.brand=brand;  149.            this.engineLv=engineLv;  150.            this.getDetail=function(){alert(this.color+", "+this.brand+", "+this.engineLv);};   //*2  151.        };  152.        Car.show=function(){alert("zoo zoo")};      //it's ok  153.        Car.prototype.show2=function(){alert("Car prototype")}; //it's ok, *3  154.  155.        var CarGas=function(color, brand, engineLv, gasNo){  156.            this.gasNo=gasNo;  157.            /*  158.            this.extend=Car;  159.            this.extend(color, brand, engineLv, gasNo);  160.            delete this.extend;  161.            */  162.             163.           //Car.call(this, color, brand, engineLv);  164.           Car.apply(this, [color, brand, engineLv]);  165.        }  166.        var car=new CarGas("back", "Mazda5", "2.0L", "97");  167.        try {  168.            alert(car.gasNo);  169.            car.getDetail();  170.            Car.show();  171.            car.show2();    //*1  172.        } catch (err) {  173.            alert(err);  174.        }  175.    }  176.  177.    /**  178.     * Extend Demo: prototype mix<br />  179.     * point1, CarGas prototype must be point to Car's <b>new Instance</b> or <b>Car.prototype</b><br />  180.     * point2, this over Car's prototype method  181.     */  182.    function demoExtend3(){  183.        var Car=function(color, brand, engineLv){  184.            this.color=color;       //*1  185.            this.brand=brand;  186.            this.engineLv=engineLv;  187.            this.getDetail=function(){alert(this.color+", "+this.brand+", "+this.engineLv);};   //*2  188.        };  189.        Car.show=function(){alert("zoo zoo")};      //it's ok  190.        Car.prototype.show2=function(){alert("Car prototype")}; //it's ok  191.  192.        var CarGas=function(color, brand, engineLv, gasNo){  193.            this.gasNo=gasNo;  194.            Car.apply(this, [color, brand, engineLv]);  195.        }  196.        //CarGas.prototype=new Car();   //*1  197.        CarGas.prototype=Car.prototype;  198.  199.        //CarGas.prototype.show2=function(){alert("CarGas prototype")}; //*2  200.        CarGas.prototype.show3=function(){alert("CarGas prototype")};  201.  202.        var car=new CarGas("back", "Mazda5", "2.0L", "97");  203.        try {  204.            alert(car.gasNo);  205.            car.getDetail();  206.            Car.show();  207.            car.show2();  208.            car.show3();  209.        } catch (err) {  210.            alert(err);  211.        }  212.    }  213.    </script>  214.  </head>  215.  <body>  216.      <form action="" >  217.          <input type="button" value="FACTORY DEMO" onclick="demoFactory()" /><br />  218.          <input type="button" value="CONSTRUCTOR DEMO" onclick="demoConstructor()" /><br />  219.          <input type="button" value="CONSTR/PROTO MIX DEMO" onclick="demoMix()" /><br />  220.          <br />  221.          <hr size="1" />  222.          <input type="button" value="EXTEND DEMO1" onclick="demoExtend1()" /><br />  223.          <input type="button" value="EXTEND DEMO2" onclick="demoExtend2()" /><br />  224.          <input type="button" value="EXTEND DEMO3" onclick="demoExtend3()" /><br />  225.      </form>  226.  </body>  227.</html>