Prototype和call(apply)结合实现继承

<html>

<head>

    <title>Test</title>

    <script type="text/javascript">

 

            function Test(a,b)

            {

                this.A = a;

                this.B = b;

                this.say = function(){

                    alert("Test-C");

                }

            }

           

           

            Test.sum = function(a,b)

            {

                return new Test(this.A + a, this.B + b);

            }

 

            Test.prototype.update = function()

            {

                alert("Test-update");

            }

           

           

            function TestChild1(){

                this.say = function(){

                    alert("TestChild1-C");

                }

               

            }

           

            //TestChild1.prototype = new Test(2, 3);

            TestChild1.prototype = new Test();

           

            function TestChild2(a, b){

                //Test.call(this, a ,b);

                this.say = function(){

                    alert("TestChild2-C");

                }

               

                Test.call(this, a ,b);

               

            }

            TestChild2.prototype = new Test();

           

           

            var test1 = new TestChild1();

            test1.say();

            test1.update();

           

           

            var test2 = new TestChild2(1, 2);

            test2.say();

            test2.update();

           

        </script>

</head>

<body>

    <div id = "testPrototype">test</div>

</body>

</html>

 

上面的代码Test是父类,TestChild1和TestChild2是子类,test1和test2分别是TestChild1和TestChild2的实例。

 

一.带参数的prototype继承方法的问题

//TestChild1.prototype = new Test(2, 3);

TestChild1.prototype = new Test();

如果TestChild1通过上面一句继承Test的话,那么TestChild1的所有实例的A和B都是固定的2和3。

所以继承的时候,带有参数的构造函数一般通过call和apply来继承,比如TestChild2继承的Test的方法。

 

二.Test.call(this, a ,b)不同位置的意义

function TestChild2(a, b){

                Test.call(this, a ,b);   ----位置1

                this.say = function(){

                    alert("TestChild2-C");

                }

               

                //Test.call(this, a ,b);     ----位置2

               

            }

 

Test.call(this, a ,b);放在位置1和位置2的区别是,位置1的话,先继承父类的say函数,子类里面的say函数会将父类的say函数覆盖,因为javascript是按照顺序执行的。位置2的话,则是先继承父类的say,子类会将父类的重写,一般是放在位置1。

 

 

三.二者结合的继承方法

function TestChild2(a, b){

                //Test.call(this, a ,b);

                this.say = function(){

                    alert("TestChild2-C");

                }

               

                Test.call(this, a ,b);

               

            }

            TestChild2.prototype = new Test();

                           

                            var test2 = new TestChild2(1, 2);

            test2.say();

            test2.update();

 

再看TestChild2的继承方法,则是结合了call和prototype两者。

如果去掉TestChild2.prototype = new Test();的话,test2.update();是访问不到的,因为Test.call(this, a ,b);只继承了构造函数。

 

四.父类函数都写在构造函数里的缺点

 

父类的函数都写在构造函数里的缺点,比如这样的形式。

function Test(a,b)

            {

                this.A = a;

                this.B = b;

                this.say = function(){

                    alert("Test-C");

                }

            }

 

say方法,每次生成一个实例,都必须在内存中生成一次,这样既占用内存效率又低。

最好的方案是,让say方法在内存中只生成一次,所有的实例都指向那个内存地址。要解决这个问题所以要采用prototype,例如下面的形式。

Test.prototype.update = function()

            {

                alert("Test-update");

            }

 

五. 总结

 

总结:通过call来调用父类带参构造函数,通过 子类.prototype=new 父类() 来继承父类的方法。如果子类想要覆盖父类的方法,可以用TestChild2.prototype.say = function(){}。

把不变的属性和方法定义在prototype上面。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。