美文网首页JavaScript 使用记录
JavaScript 继承 6 寄生组合式继承

JavaScript 继承 6 寄生组合式继承

作者: 赵者也 | 来源:发表于2017-12-18 09:36 被阅读33次

    前面介绍的组合继承最大的问题就是无论什么情况下,都会调用两次父类型的构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。没错,子类型最终会包含父类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性:

            function SuperColors(colorName) {
                if (typeof colorName != "undefined") {
                    this.colors = ["red", "green", "blue", colorName];
                } else {
                    this.colors = ["red", "green", "blue"];
                }
            }
            SuperColors.prototype.sayColors = function () {
                console.log(this.colors);
            };
            function SubColors(colorName, level) {
                // 继承属性
                SuperColors.call(this, colorName); // 第2次调用 SuperColors
    
                this.level = level;
            }
    
            SubColors.prototype = new SuperColors(); // 第1ss次调用 SuperColors
    
            SubColors.prototype.sayLevel = function () {
                console.log(this.level);
            };
    

    解决这个问题的办法是使用寄生组合式继承。所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

    其思路是:不必为了指定子类型的原型而调用父类型的构造函数,我们所需要的无非就是父类型原型的一个副本而已。本质上,就是使用寄生式继承来继承父类型的原型,然后再将结果指定给子类型的原型。

    寄生组合式继承的基本模式如下:

            function inheritPrototype(subType, superType) {
                var prototype = Object.create(superType.prototype); // 创建对象
                prototype.constructor = subType;  // 增强对象
                subType.prototype = prototype; // 指定对象
            }
    

    这个实例中 inheritPrototype 函数实现了寄生组合式继承的最简单形式:

    1. 创建父类型原型的一个副本;
    2. 为创建的副本添加 constructor 属性,从而弥补因重写原型而失去的默认的 constructor 属性;
    3. 将新创建的对象(即副本)赋值给子类型的原型。

    这样,我们就可以调用 inheritPrototype 函数来修改前面的组合继承的例子了:

    function SuperColors(colorName) {
                if (typeof colorName != "undefined") {
                    this.colors = ["red", "green", "blue", colorName];
                } else {
                    this.colors = ["red", "green", "blue"];
                }
            }
            SuperColors.prototype.sayColors = function () {
                console.log(this.colors);
            };
            function SubColors(colorName, level) {
                // 继承属性
                SuperColors.call(this, colorName);
    
                this.level = level;
            }
    
            inheritPrototype(SubColors, SuperColors);
    
            SubColors.prototype.sayLevel = function () {
                console.log(this.level);
            };
    
            var instance1 = new SubColors("gray", 0);
            instance1.colors.push("white");
            instance1.sayColors();
            instance1.sayLevel();
    
            var instance2 = new SubColors("black", 1);
            instance2.sayColors();
            instance2.sayLevel();
    

    输出结果:

    输出结果

    这个例子的高效率体现在它只调用了一次 SuperColors 构造函数,并且因此避免了在 SubColors.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。

    相关文章

      网友评论

        本文标题:JavaScript 继承 6 寄生组合式继承

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