zoukankan      html  css  js  c++  java
  • 面向对象与原型5---继承

    1.用原型链实现继承 最普通 但是没有办法传参,没有办法共享方法

    继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继
    承:一个是接口实现,一个是继承。而 ECMAScript 只支持继承,不支持接口实现,而实现
    继承的方式依靠原型链完成。

    原型链是由原型加对象构造之间的关系结构形成的像一个链条一样

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

    //继承,通过原型链实现

    function Box() { //Box 构造 被继承的函数叫做超类型(父类)
    this.name = 'Lee';
    }
    function Desk() { //Desk 构造 继承的函数称为子类型(子类,派生类)。
    this.age = 100;
    }

    var desk = new Desk();

    alert(desk.age);   //100

    alert(desk.name);   //undefined  

    //通过原型链继承,超类型实例化后的对象实例,赋值给子类型的原型属性即可

    //new Box()会将Box构造里的信息和原型里的信息都交给Desk
    Desk.prototype = new Box(); //Desk 继承了 Box,通过原型,形成链条  超类型new出来的东西交给子类型的原型
    var desk = new Desk();
    alert(desk.age);
    alert(desk.name); // Lee 得到被继承的属性


    function Table() { //Table 构造
    this.level = 'AAAAA';
    }
    Table.prototype = new Desk(); //继续原型链继承
    var table = new Table();
    alert(table.name); //Lee  继承了 Box 和 Desk

    Desk的原型得到的是Box的构造加原型里的信息(图中水平第一个和第二个框),Table的原型又得到了Desk的构造和原型里的信息,所以最终的  Table得到了上面所有的信息。

    如果要实例化 table,那么 Desk 实例中有 age=100,原型中增加相同的属性 age=200,
    最后结果是多少呢?
    Desk.prototype.age = 200; //实例和原型中均包含 age

    alert(table.age);  //输出100  就近原则  实例里面有就返回,没有就去查找原型

    从属关系

    以上原型链继承还缺少一环,那就是 Obejct,所有的构造函数都继承自 Obejct。而
    继承 Object 是自动完成的,并不需要程序员手动继承。

    //子类型从属于自己或者他的超类型

    alert(desk instanceof Desk);  //true
    alert(desk instanceof Box);  //true

    alert(desk instanceof Object);  //true

    继承也有之前问题,比如字面量重写原型会中断关系,使用引用类型的原型时,并且子类型还无法给超类型传递参数。

    2.第二种继承方法——借用构造函数继承 即对象冒充继承 解决了传参的问题  但是没有解决共享的方法

    为了解决引用共享和超类型无法传参的问题,我们采用一种叫借用构造函数的技术,或
    者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题。

    //使用对象冒充

    function Box(name,age) {
    this.name = name;
    this.age = age;

    }

    Box.prototype.family='家庭';
    function Desk(name,age) {
    Box.call(this, name,age); //this代表了Desk本身的类   对象冒充,给超类型传参 因此 Desk就可以冒充Box了 对象冒充只能继承构造里的信息,继承不了原型里的信息

    }

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

    alert(desk.name);  //输出 Lee   说明Desk冒充了Box

    alert(desk.family);  //undefined   原型里的信息继承不过来

    //引用类型放到构造函数里就不会共享

    function Box(name,age) {
    this.name = name;
    this.age = age;

    this.family = ['哥哥','姐姐','妹妹'];

    }

    function Desk(name,age){

    Box.call(this,name,age);

    }

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

    desk.family.push('弟弟');

    alert(desk.family);  //输出 哥哥 姐姐 妹妹 弟弟

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

    alert(desk2.family);  //输出  哥哥 姐姐 妹妹  引用类型放到构造函数里就不会共享

    (参看面向对象与原型4---原型

    function Box(name,age) {
    this.name = name;
    this.age = age;

    this.family = ['哥哥','姐姐','妹妹'];

    this.run = function(){

    }

    }

    function Desk(name,age){

    Box.call(this,name,age);

    }

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

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

    //构造函数里的方法,放在构造里,每次实例化都会分配一个内存地址,浪费,所以最好放在原型里,保证多次实例化只有一个地址。

    function Box(name,age) {
    this.name = name;
    this.age = age;

    this.family = ['哥哥','姐姐','妹妹'];

    }

    Box.prototype.run = function(){

      return this.name+this.age;

    }

    function Desk(name,age){

    Box.call(this,name,age);

    }

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

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

    以上两次实例化保证了一个地址

    但是

    alert(desk.run());  //not a function  因为通过对象冒充继承不到原型里的东西

    3.组合模式实现继承(结合前两种)----最常用

    对象冒充 结合 原型链  解决传参和方法共享的问题
    借用构造函数虽然解决了刚才两种问题,第一个:引用保持独立。第二个:可以传参。但没有原型,复用则无从谈起。所以,我们需
    要原型链+借用构造函数的模式,这种模式成为组合继承。

    function Box(name,age) {
    this.name = name;
    this.age = age;

    this.family = ['哥哥','姐姐','妹妹'];

    }

    Box.prototype.run = function(){

      return this.name+this.age;

    }

    function Desk(name,age){  

    Box.call(this,name,age);  //对象冒充只继承构造里的

    }

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

    4.原型式继承

    还有一种继承模式叫做:原型式继承;这种继承借助原型并基于已有的对象创建新对象,
    同时还不必因此创建自定义类型。

    //临时中转函数

    function obj(o){ //o表示将要传递进入的一个对象实例 

      function F(){}  //F构造是一个临时新建的对象,用来存储传递进来的对象

      F.prototype=o;  //将o对象实例赋值给F构造的原型

      return new F();  // 最后返回这个得到传递过来对象的对象实例

    }

    var box={  //这是字面量的声明方式,相当于 var box=new Box();

    name:'Lee',

    age:100,

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

    }

    var box1=obj(box);  //box1就等于new出来的F

    alert(box1.name);  //Lee

    box1.family.push('弟弟');

    alert(box1.family);  //哥哥姐姐妹妹弟弟

    var box2=obj(box);

    alert(box2.family);  //哥哥姐姐妹妹弟弟 引用类型的属性共享了  因为把box全部放到F.prototype里了

    标题说的原型式继承实际上是F继承了box   F.prototype=o 其实就相当于Desk.prototype= new Box()

    这种方法其实就是原型链继承 意思是一样的  只不过是改写了方式

    5.寄生式继承 =原型式+工厂模式  ,目的是为了封装创建对象的过程

    //临时中转函数

    function obj(o){ //o表示将要传递进入的一个对象实例 

      function F(){}  //F构造是一个临时新建的对象,用来存储传递进来的对象

      F.prototype=o;  //将o对象实例赋值给F构造的原型

      return new F();  // 最后返回这个得到传递过来对象的对象实例

    }

    //寄生函数

    function create(o){

    var f=obj(o);

    f.run = function(){

      return this.name;

    }

    return f;

    }

    var box={  //这是字面量的声明方式,相当于 var box=new Box();

    name:'Lee',

    age:100,

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

    }

    var box1=create(box);

    alert(box1.name);

    alert(box1.run());//Lee

    组合式继承是 JavaScript 最常用的继承模式;但,组合式继承也有一点小问题,就是超
    类型在使用过程中会被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的
    内部。

    function Box(name) {
    this.name = name;
    this.arr = ['哥哥','妹妹','父母'];
    }
    Box.prototype.run = function () {
    return this.name;
    };
    function Desk(name, age) {
    Box.call(this, name); //第二次调用 Box
    this.age = age;
    }
    Desk.prototype = new Box(); //第一次调用 Box
    以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

    6.寄生组合继承

    //临时中转函数

    function obj(o){ 

      function F(){}  

      F.prototype=o;  

      return new F();  

    }

    //寄生函数

    function create(box,desk){

    var f=obj(box.prototype);  //调用obj函数

    f.constructor= desk;  //调整原型构造指针

    desk.prototype =f;

    }

    function Box(){

      this.name=name;

      this.age=age;

    }

    Box.prototype.run=function(){

      return this.name+this.age;  //方法放在原型 让每次实例化的时候 地址保持一致

    }

    function Desk(name,age){

    Box.call(this,name,age);

    }

    //通过寄生组合继承来实现继承

    create(Box,Desk);  //这句话用来替代Desk.prototype=new Box();

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

    alert(desk.run());  //Lee100

  • 相关阅读:
    https://rll.berkeley.edu/gps/
    论文阅读:Learning Manipulation Tasks from Vision-based Teleoperation
    Qt编写安防视频监控系统65-子模块9数据调试
    Qt编写安防视频监控系统64-子模块8飞行轨迹
    Qt编写可视化大屏电子看板系统22-平滑曲线图
    Qt编写安防视频监控系统63-子模块7悬浮地图
    OpenCV使用双边滤波以及锐化算子实现图片的美颜以及提升清晰度操作
    OpenCV实现均值滤波和高斯滤波
    OpenCV绘制线、圆、椭圆、矩形
    OpenCV利用像素点操作调整图像亮度
  • 原文地址:https://www.cnblogs.com/mabelstyle/p/3721075.html
Copyright © 2011-2022 走看看