<
>

JS继承与工厂构造及原型设计模式详解

2022-07-08 11:53:08 来源:易采站长站 作者:

目录
序言正文结语

序言

我们在前一篇文章《JS精粹,原型链继承和构造函数继承的>

在另一篇文章《蓦然回首,“工厂、构造、原型”设计模式,正在灯火阑珊处》,提到了:我们用于创建对象的三种设计模式:工厂设计模式、构造设计模式、原型设计模式;

至此,我们可以明显的感受到:JS 要实现面向对象(继承的能力),离不开这 3 种设计模式;

原型链 + 构造函数 = 组合继承

本篇带来一个新的继承方式:寄生继承,它由工厂模式和构造函数模式组成,即

工厂+构造函数 = 寄生继承

正文

正是由于:原型链继承和构造函数继承的>

    原型链继承:所有继承的属性和方法都会在对象实例间共享,无法做到实例私有。构造函数继承:子类不能访问父类原型上的方法。

    组合继承应运而生:

    function SuperType(name){
         this.name = name;
         this.colors = ["red", "blue", "green"];
    }
    function SubType(name, age){
         SuperType.call(this, name) // 构造函数继承 (两次调用父类构造函数)
         this.age = age;
    }
    SuperType.prototype.sayName = function() {
         console.log(this.name);
    }
    SubType.prototype = new SuperType() // 原型链继承 (一次调用父类构造函数)
    SubType.prototype.sayAge = function() {
    	 console.log(this.age);
    }
    let s1 = new SubType("Nicholas", 29)
    let s2= new SubType("Greg", 27)
    s1.colors.push("yellow")
    console.log(s1.colors) // ['red', 'blue', 'green', 'yellow']
    console.log(s2.colors) // ['red', 'blue', 'green']
    s1.sayName() // Nicholas
    s2.sayName() // Greg
    s1.sayAge() // 29
    s2.sayAge() // 27
    

    但是呢?这样做,会有效率问题,父类构造函数始终会被调用两次:一次是在子类构造函数中调用,另一次在是创建子类原型时调用。

    本质上,子类原型最终是要包含超类对象的所有实例属性,子类构造函数只要在执行时重写自己的原型就行了。

    这个时候有一个新的思路!

    不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。使用寄生式继承来继承父 类原型,然后将返回的新对象赋值给子类原型。

    核心代码是:通过工厂的方式,增强一个新对象:

    function createAnother(original){
         let clone = Object(original); // 通过调用函数创建一个新对象
         clone.sayHi = function() { // 以某种方式增强这个对象
             console.log("hi");
         };
         return clone; // 返回这个对象
    }
    

    将组合代码改造一下,完整代码是:

    function inheritPrototype(subType, superType) {
         let prototype = Object(superType.prototype); // 创建对象
         prototype.constructor = subType; // 增强对象
         subType.prototype = prototype; // 赋值对象
    }
    function SuperType(name) {
         this.name = name;
         this.colors = ["red", "blue", "green"];
    }
    function SubType(name, age) {
         SuperType.call(this, name); // 构造函数继承(只调了一次)
         this.age = age;
    }
    SuperType.prototype.sayName = function() {
         console.log(this.name);
    };
    inheritPrototype(SubType, SuperType); // 寄生继承
    SubType.prototype.sayAge = function() {
         console.log(this.age);
    };
    let s1 = new SubType("Nicholas", 29)
    let s2= new SubType("Greg", 27)
    s1.colors.push("yellow")
    console.log(s1.colors) // ['red', 'blue', 'green', 'yellow']
    console.log(s2.colors) // ['red', 'blue', 'green']
    s1.sayName() // Nicholas
    s2.sayName() // Greg
    s1.sayAge() // 29
    s2.sayAge() // 27
    

    这里只调用了一次 SuperType 构造函数,避免了 SubType.prototype 上不必要也用不到的属性;而且,原型链仍然保持不变,instanceof 操作符和 isPrototypeOf() 方法正常有效。

    寄生式组合继承可以算是【引用类型】继承的最佳模式

    os:不过这里的增强写法,理解起来真是怪,为什么父类的显示原型的构造函数等于子类?

    SuperType.prototype.constructor=== SubType // true
    

    大概是为了,通过寄生实现:父类、子类都由同一函数构造;

    SubType === SubType.prototype.constructor // true
    SuperType.prototype.constructor === SubType.prototype.constructor // true
    

    结语

    只要是写>

    原型链 + 构造函数 = 组合继承

    工厂+构造函数 = 寄生继承;

    组合继承和寄生继承是最常用的两种继承方式。

    ......

    u1s1,class 出来前,写 JS 实现继承,是真滴麻烦QAQ

    以上就是JS继承与工厂构造及原型设计模式详解的详细内容,更多关于JS继承与设计模式的资料请关注易采站长站其它相关文章!

暂时禁止评论

微信扫一扫

易采站长站微信账号