美文网首页
JavaScript 继承(五)寄生式、组合寄生继承

JavaScript 继承(五)寄生式、组合寄生继承

作者: BertFu | 来源:发表于2016-11-18 00:24 被阅读0次

    寄生式(parasitic)继承是与原型式继承紧密相关的一种思路。寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

    function object(o) {
        function F(){}
        F.prototype = o;
        return new F();
    }
    
    function createAnother(original) {
        // 通过调用函数创建一个新对象
        var clone = object(original);  
        // 以某种方式来增强这个对象
        clone.sayHi = function() {
            alert("hi");
        }
    
        return clone;
    }
    

    上例中,createAnother() 函数接收了一个参数,作为新对象继承的对象。然后,把这个对象(original)传递给 object() 函数,将返回的结果赋值给 clone。再为 clone 对象添加一个新方法 sayHi(),最后返回 clone 对象。

    var person = {
        name: "Bert",
        friends: ["Shelby", "Court", "Van"]
    };
    
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi(); // Hi
    

    上例中, person返回了一个新对象 ---- anotherPerson。新对象不仅具有 person 的所有属性和方法,而且还有自己的 sayHi() 方法。

    在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。例子中使用的 object() 函数不是必须的,可以使用任何能够返回新对象的函数都适用于此模式。

    使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点和构造函数模式类似。

    寄生组合式继承

    组合式继承是 JavaScript 最常用的继承模式;不过它也有自己的不足。组合式继承最大的问题就是无论什么情况下,都会调用两次超类型构造函数;一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

    子类型最终会包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性。

    function SuperType(name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    SuperType.prototype.sayName = function() {
        alert(this.name);
    }
    
    function SubType(name, age) {
        SuperType.call(this, name); // 第二次调用 SuperType()
        this.age = age;
    }
    
    SuperType.prototype = new SuperType(); // 第一次调用 SuperType()
    SubType.prototype.sayAge = function() {
        alert(this.age);
    }
    

    上例中,有两组 name 和 colors 属性:一组在实例上,一组在 SubType 原型中。这就是调用两次 SuperType 构造函数的结果,通过寄生组合式继承可以解决该问题。

    寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。(不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本)本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

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

    上例中的 inheritPrototype() 函数实现了寄生组合式继承的最简单形式。

    1. 接收两个参数:子类型构造函数和超类型构造函数。
    2. 在函数内部,第一步是创建超类型原型的一个副本。第二部是为创建的副本添加 constructor 属性,从而弥补因重写原型而失去的默认的 constructor 属性。
    3. 将新创建的对象(副本)赋值给子类型的原型。
    function SuperType(name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    SuperType.prototype.sayName = function() {
        alert(this.name);
    }
    
    function SubType(name, age) {
        SuperType.call(this, name);
    
        this.age = age;
    }
    
    inheritPrototype(SubType, SuperType);
    
    SubType.prototype.sayAge = function( {
        alert(this.age);
    })
    

    这个例子的高效体现在它只调用了一次 SuperType 构造函数,并且因此避免了在 SubType.prototype 上面创建不需要的、多余的属性。与此同时,原型链还能保持不变;能够正常使用 instanceof 和 isPrototypeOf()。

    备注:对寄生组合式继承的看法是,通过代码模拟原型链的结构

    每个原型链无非就是 proto 属性指向的原型连城的链,既然我们能够通过 prototype 指定对象的原型链,那么同样的指定对象的构造器,就相当于完美实现一个原型继承了。

    而之前所涉及到的: 1、借用构造函数继承,实际上就是通过指定对象的构造函数,初始化一些需要的属性;2、组合式继承就是使用 prototype 加上 构造函数;3、寄生式继承通过函数内部做处理继承所需要的函数,在内部添加自定义属性,达到继承效果。

    这些都只是在变相的改变对象自身的 prototype,所以只要明白 prototype 指向什么,代表什么,那么玩转 js 的继承就不在话下了。

    相关文章

      网友评论

          本文标题:JavaScript 继承(五)寄生式、组合寄生继承

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