美文网首页
JS_继承进阶

JS_继承进阶

作者: learninginto | 来源:发表于2019-12-06 20:01 被阅读0次

day19_JS_继承进阶

1.JS中的继承

继承是面向对象中一个比较核心的概念。

其他正统面向对象语言都会有两种方式实现继承:一个是接口实现,一个是继承

而JS只是继承,不支持接口实现,而实现继承的方式依靠原型链完成。

原型链继承.png

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

继承的函数称为子类型(子类,派生类)。

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

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

  • 冒充式继承

    function Box(_a) {
        this.a = _a;
        this.play();
    }
    // 添加一个实例化属性和方法
    Box.prototype.a = 10;
    Box.prototype.play = function () {
    
    }
    
    // 添加一个静态属性和方法
    Box.b = 20;
    Box.run = function () {
        
    }
    
    function Ball(_a) {
        //此处会出错,this.play is not a function
        Box.call(this, _a);
    }
    
    var b = new Ball(10);
    console.loe(b);
    
  • 组合式继承

    function Box(_a) {
        console.log("aaa");//打印两次aaa
        this.a = _a;
        this.play();
    }
    // 添加一个实例化属性和方法
    Box.prototype.a = 10;
    Box.prototype.play = function () {
    
    }
    // 添加一个静态属性和方法
    Box.b = 20;
    Box.run = function () {
    
    }
    function Ball(_a) {
        // Box.call(this,_a);
        this.a = _a;
        this.play();
    }
    Ball.prototype = new Box();
    // 将原来constructor中的Box替换为Ball
    Ball.prototype.constructor = Ball;
    var b = new Ball(10);
    console.log(b);
    // 缺点:原型中a的属性值没有继承到
    
  • 原型式继承

    function Box(_a) {
       console.log("aaa");//打印两次aaa
       this.a = _a;
       this.play();
    }
    // 添加一个实例化属性和方法
    Box.prototype.a = 10;
    Box.prototype.play = function () {
    
    }
    
    // 添加一个静态属性和方法
    Box.b = 20;
    Box.run = function () {
       
    }
    function Ball(_a) {
       Box.call(this, _a);
    }
    
    function F() { }
    F.prototype = Box.prototype;
    Ball.prototype = new F();
    Ball.prototype.constructor = Ball;
    
    let b = new Ball(10);
    console.log(b);
    
  • 寄生式继承

    • 版本一(相对容易理解)
    function Box(_a) {
        this.a = _a;
        this.play();
    }
    // 添加一个实例化属性和方法
    Box.prototype.a = 10;
    Box.prototype.play = function () {
    
    }
    
    // 添加一个静态属性和方法
    Box.b = 20;
    Box.run = function () {
    
    }
    
    function extend(subClass, supClass) {
        // 创建一个中间替代类,防止多次执行父类(超类)的构造函数
        function F() { }
        // 将父类的原型赋值给这个中间替代类
        F.prototype = supClass.prototype;
        // 将原子类的原型保存
        var proto = subClass.prototype;
        // 将子类的原型设置为中间替代类的实例对象
        subClass.prototype = new F();
        // 将原子类的原型复制到子类原型上,合并超类原型和子类原型的属性方法
        var names = Object.getOwnPropertyNames(proto);
        for (var i = 0; i < names.length; i++) {
            var desc = Object.getOwnPropertyDescriptor(proto, names[i]);
            Object.defineProperty(subClass.prototype, names[i], desc);
        }
        // 设置子类的构造函数时自身的构造函数,以防止因为设置原型而覆盖构造函数(防止)
        subClass.prototype.constructor = subClass;
        // 给子类的原型中添加一个属性,可以快捷的调用到父类的原型方法
        subClass.prototype.superClass = supClass.prototype;
        // 如果父类的原型构造函数指向的不是父类构造函数,重新指向(防止)
        if (supClass.prototype.constructor !== supClass) {
            supClass.prototype.constructor = supClass;
        }
    }
    
    function Ball(_a) {
        this.superClass.constructor.call(this, _a);
    }
    Ball.prototype.play = function () {
        //执行超类的play方法
        this.superClass.play.call(this);
    }
    Object.defineProperty(Ball.prototype, "d", {
        value: 20
    })
    
    extend(Ball, Box);
    var b = new Ball(10);
    console.log(b);
    
    • 版本二(ES5)
    function Box(_a) {
        this.a = _a;
        this.play();
    }
    // 添加一个实例化属性和方法
    Box.prototype.a = 10;
    Box.prototype.play = function () {
    
    }
    
    // 添加一个静态属性和方法
    Box.b = 20;
    Box.run = function () {
    
    }
    Function.prototype.extend = function (supClass) {
        function F() { }
        F.prototype = supClass.prototype;
        var proto = this.prototype;
        this.prototype = new F();
        var names = Object.getOwnPropertyNames(proto);
        for (var i = 0; i < names.length; i++) {
            var desc = Object.getOwnPropertyDescriptor(proto, names[i]);
            Object.defineProperty(this.prototype, names[i], desc);
        }
        this.prototype.constructor = this;
        this.prototype.superClass = supClass.prototype;
        if (supClass.prototype.constructor !== supClass) {
            supClass.prototype.constructor = supClass;
        }
    }
    
    function Ball(_a) {
        this.superClass.constructor.call(this, _a);
    }
    Ball.prototype.play = function () {
        this.superClass.play.call(this);
    }
    Object.defineProperty(Ball.prototype, "d", {
        value: 20
    })
    
    Ball.extend(Box);
    var b = new Ball(10);
    console.log(b);
    
  • 还有其他混入式继承等,博主就不一一罗列了~~~

相关文章

网友评论

      本文标题:JS_继承进阶

      本文链接:https://www.haomeiwen.com/subject/fuaegctx.html