• JavaScript继承总结


    继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而 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
    原型链继承流程图

    如果要实例化 table,那么 Desk 实例中有 age=100,原型中增加相同的属性 age=200,
    最后结果是多少呢?
    Desk.prototype.age = 200; //实例和原型中均包含 age
    PS:以上原型链继承还缺少一环,那就是 Obejct,所有的构造函数都继承自 Obejct。而继承 Object 是自动完成的,并不需要程序员手动继承。

    经过继承后的实例,他们的从属关系会怎样呢?
    alert(table instanceof Object); //true
    alert(desk instanceof Table); //false,desk 是 table 的超类
    alert(table instanceof Desk); //true
    alert(table instanceof Box); //true
    在 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 () {
    return this.name;
    };
    function Desk(name, age) {
    Box.call(this, name); //第二次调用 Box
    this.age = age;
    }
    Desk.prototype = new Box(); //第一次调用 Box
    以上代码是之前的组合继承,那么 寄生组合继承,解决了两次调用的问题
    function obj(o) {
      function F() {}
      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;
    }
      inPrototype(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); //引用问题解决

  • 相关阅读:
    KnowYoueSelf
    计算机组成原理--海明码的编码和校验方法(易懂)
    html5新特性
    web前端性能优化
    web标准
    《王者归来》笔记-安全&性能01
    vue核心最基本功能
    BOM&DOM
    JavaScript-语法
    前端04
  • 原文地址:https://www.cnblogs.com/wennice/p/6374681.html
Copyright © 2020-2023  润新知