资讯专栏INFORMATION COLUMN

JS面向对象的程序设计之继承的实现-寄生组合式继承

y1chuan / 3173人阅读

摘要:组合继承最大的问题就是无论在什么情况下,都会调用两次超类型构造函数一次是在创建子类型原型的时候。好在,我们已经找到了解决这个问题方法寄生组合式继承所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

寄生组合式继承

组合继承是JavaScript最常用的继承模式。

不过,它也有自己的不足。

组合继承最大的问题就是无论在什么情况下,都会调用两次超类型构造函数:

一次是在创建子类型原型的时候。

另外一次是在子类型构造函数内部。

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

function SuperType(name) {
    this.name = name;
    this.colors = ["red", "green", "blue"];
}

SuperType.prototype.sayName = function(){
    console.log(this.name);
}

function SubType(name, age) {
    SuperType.call(this, name); //第二次调用父类型
    this.age = age;
}

SubType.prototype = new SuperType(); // 第一次调用父类型

/*
//到这里SubType的原型
SubType.prototye = {
    name: undefined,
    colors: ["red", "green", "blue"],
    __proto__: {
        constructor: SuperType,
        sayName: function(){
            console.log(this.name);
        }
    }

*/

SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
    console.log(this.age);
}

/*
//到这里SubType的原型
SubType.prototye = {
    name: undefined,
    colors: ["red", "green", "blue"],
    constructor: SubType,
    sayAge: function() {
        console.log(this.age);
    },
    __proto__: {
        constructor: SuperType,
        sayName: function(){
            console.log(this.name);
        }
    }
*/

var sub = new SubType();

/*
// SubType的实例对象sub,其实是这样的
sub = {
    name: undefined,
    colors: ["red", "green", "blue"],
    age: undefined,
    __proto__: {
        name: undefined,
        colors: ["red", "green", "blue"],
        constructor: SubType,
        sayAge: function() {
            console.log(this.age);
        },
        __proto__: {
            constructor: SuperType,
            sayName: function(){
                console.log(this.name);
            }
        }
    }
}

*/

在第一次调用SuperType构造函数时,SubType.prototype会得到两个属性:name和colors;它们都是SuperType的实例属性, 只不过现在位于SubType的原型中。

如果我们调用SubType构造函数时,又会调用一次SuperType构造函数,这一次有在新对象上创建了实例属性name和colors。于是,这两个属性就屏蔽了原型中的两个同名属性。

有两组name和colors属性: 一组在实例上,一组在SubType原型中。
这就是调用两次SuperType函数的结果。

好在,我们已经找到了解决这个问题方法——寄生组合式继承

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

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

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

function SuperType(name) {
    this.name = name;
    this.colors = ["red", "green", "blue"];
}

SuperType.prototype.sayName = function(){
    console.log(this.name);
}

function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}

function inheritPrototype(SubType, SuperType){
    var prototype = object(SuperType.prototype);
    prototype.constructor = SubType;
    SubType.prototype = prototype;
}


inheritPrototype(SubType, SuperType);

var instance  =  new SubType("Shaw", 18);

instance.sayName(); //"Shaw"

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

这个函数接收两个参数: 子类型构造函数和超类型构造函数。

在函数内部,第一步是创建超类型原型的一个副本。第二步是为创建的副本添加constructor属性,从而弥补因为重写原型而失去的默认的constructor属性。 最后一步,将新创建的对象(副本)赋值给子类型的原型。

这样,我们就可以调用inheritPrototype()函数的语句,去替换前面例子中为子类型原型赋值的语句了。

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

因此,还能够正常使用instanceof和isPrototypeOf()。

开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98652.html

相关文章

  • 面向对象程序设计继承

    摘要:以下是几种中实现继承的方式方法它们也是各自有各自的优缺点选择哪一种根据自己的应用而定最适合自己的才是最好的通过原型链继承通过原型对象继承缺点引用类型的值在原型中会被所有实例共享不能向超类的构造函数中传递参数借用构造函数继承借用构造函数继承是 以下是几种js中实现继承的方式方法,它们也是各自有各自的优缺点,选择哪一种根据自己的应用而定,最适合自己的才是最好的. 通过原型链继承 funct...

    魏明 评论0 收藏0
  • 《javascript高级程序设计继承实现方式

    摘要:寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部已某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。 这篇本来应该是作为写JS 面向对象的前奏,只是作为《javascript高级程序设计》继承一章的笔记 原型链 code 实现 function SuperType() { this.colors = [red,blu...

    cppprimer 评论0 收藏0
  • JS学习笔记(第6章)(面向对象继承——JS继承六大方式)

    摘要:除此之外,在超类型的原型中定义的方法,对子类型而言也是不可兼得,结果所有类型都只能用构造函数模式。创建对象增强对象指定对象继承属性这个例子的高效率体现在它只调用了一次构造函数。 1、原型链 原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。构造函数、原型和实例的关系:每个构造函数都有一个原型对象;原型对象都包含着一个指向构造函数的指针;实例都包含一个指向原型对象的...

    lscho 评论0 收藏0
  • JavaScript面向对象---原型链继承

    摘要:因为这造成了继承链的紊乱,因为的实例是由构造函数创建的,现在其属性却指向了为了避免这一现象,就必须在替换对象之后,为新的对象加上属性,使其指向原来的构造函数。这个函数接收两个参数子类型构造函数和超类型构造函数。 最近一直在研究js面向对象,原型链继承是一个难点,下面是我对继承的理解以下文章借鉴自CSDN季诗筱的博客 原型链继承的基本概念: ES中描述了原型链的概念,并将原型链作为实现...

    vspiders 评论0 收藏0
  • JavaScript深入各种继承

    摘要:通常有这两种继承方式接口继承和实现继承。理解继承的工作是通过调用函数实现的,所以是寄生,将继承工作寄托给别人做,自己只是做增强工作。适用基于某个对象或某些信息来创建对象,而不考虑自定义类型和构造函数。 一、继承的概念 继承,是面向对象语言的一个重要概念。通常有这两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。 《JS高程》里提到:由于函数没有签名,...

    tomlingtm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<