面向对象与原型(三)

继承:

      继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继

承: 一个是接口实现, 一个是继承。 而ECMAScript只支持继承, 不支持接口实现,而实

现继承的方式依靠原型链完成。

       function Box(){                       //Box构造
             this.name='Lee';
       }
       function Desk(){                    //Desk构造
             this.age=100;
       }
       Desk.prototype=new Box();           //Desc继承了Box, 通过原型, 形成链条
       var desk=new Desk();
       alert(desk.age);
       alert(desk.name);              //得到被继承的属性
       function Table(){               //Table构造
             this.level='AAAAA';
       }
      Table.prototype=new Desk(); //继续原型链继承
      var table=new Table();
      alert(table.name);               //继承了Box和Desk

 

                                                 原型链继承图

 

 

      在JavaScript里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为

子类型(子类,派生类)。继承也有之前问题,比如字面量重写原型会中断关系, 使用引用类型的原型

,并且子类型还无法给超类型传递参数。为了解决引用共享和超类型无法传参的问题,我们采用一种

叫借用构造函数的技术,或者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题。

      function Box(age){

            this.name=['Lee','Jack','Hello']

            this.age=age;

      }

      function Desk(age){

            Box.call(this,age);       //对象冒充,给超类型传参

      }

      var desk = new Desk(200);

      alert(desk.age);

      alert(desk.name);

      desk.name.push('AAA');    //添加的新数据,只给 desk

      alert(desk.name);

      借用构造函数虽然解决了刚才两种问题, 但没有原型, 复用则无从谈起。 所以, 我们需要

原型链+借用构造函数的模式,这种模式成为组合继承。

      function Box(age) {

            this.name = ['Lee', 'Jack', 'Hello']

            this.age = age;

     }

     Box.prototype.run = function () {

           return this.name + this.age;

     };

     function Desk(age) {

           Box.call(this, age); //对象冒充

     }

     Desk.prototype = new Box(); //原型链继承

     var desk = new Desk(100);

     alert(desk.run());

     还有一种继承模式叫做:原型式继承;这种继承借助原型并基于已有的对象创建新对象,

同时还不必因此创建自定义类型。

      function obj(o) { //传递一个字面量函数

            function F() {} //创建一个构造函数

            F.prototype = o; //把字面量函数赋值给构造函数的原型

            return new F(); //最终返回出实例化的构造函数

      }

      var box = { //字面量对象

           name : 'Lee',

           arr : ['哥哥','妹妹','姐姐']

       };

       var box1 = obj(box); //传递

       alert(box1.name);

       box1.name = 'Jack';

       alert(box1.name);


       alert(box1.arr);

       box1.arr.push('父母');

       alert(box1.arr);

       var box2 = obj(box); //传递

       alert(box2.name);

       alert(box2.arr); //引用类型共享了

       寄生式继承把原型式+工厂模式结合而来,目的是为了封装创建对象的过程。

       function create(o) { //封装创建过程

             var f= obj(o);

             f.run= function () {

                   return this.arr; //同样,会共享引用

             };

             return f;

        }

      组合式继承是 JavaScript最常用的继承模式; 但, 组合式继承也有一点小问题, 就是超

型在使用过程中会被调用两次: 一次是创建子类型的时候, 另一次是在子类型构造函数的部。

      function Box(name) {

            this.name = name;

            this.arr = ['哥哥','妹妹','父母'];

      }

      Box.prototype.run= function() {

            returnthis.name;

      };

      function Desk(name, age) {

            Box.call(this, name); //第二次调用 Box

            this.age = age;

      }

      Desk.prototype = newBox(); //第一次调用 Box

      以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

      function obj(o) {

            functionF() {}

            F.prototype= o;

            return new F();

      }

      function create(box,desk){

            var f=obj(box.prototype);

            f.constructor=desk;

            desk.prototype=f;

      }

      function Box(name){

            this.name=name;

            this.arr=['哥哥','妹妹','父母'];

      }

      Box.prototype.run=function(){

            return this.name;

      };

      function Desk(name,age){

            Box.call(this,name);

            this.age=age;

       }

       create(Box,Desk); //通过这里实现继承

       var desk=new Desk('Lee',100);

       desk.arr.push('姐姐');

       alert(desk.arr);

       alert(desk.run()); //只共享了方法

       var desk2=new Desk('Jack',200);

       alert(desk2.arr); //引用问题解决

 

posted @ 2016-01-13 16:49  西风.烈马  阅读(153)  评论(0编辑  收藏  举报