【读书笔记】读《JavaScript模式》 - 函数复用模式之类式继承模式

  实现类式继承的目标是通过构造函数Child()获取来自于另外一个构造函数Parent()的属性,从而创建对象。

  1.类式继承模式#1 —— 默认方式(原型指向父函数实例)

function Parent(name) {
    this.name = name || 'king';
}
Parent.prototype.say = function () {
    return this.name;
};

function Child(name) {
    this.name = name;
}

function inherit(C, P) {
    /**
     * 1>该继承模式同时继承了两个对象的属性,即添加到this的属性以及原型属性。
     *     在绝大多数的时候,并不需要这些自身的属性,因为它们很可能是指向一个特定的实例,而不是复用。
     *     但是我们可以提供覆盖属性的方式进行实例化更新。
     * 2>对于构造函数的一般经验法则是:应该将可服用的成员添加到原型中。
     */
    C.prototype = new P();
}
inherit(Child, Parent);

var child = new Child('kingChild');
console.log(child.say());    //king

  2.类式继承模式#2 —— 借用构造函数

function Parent(name) {
    this.name = name || 'king';
}
Parent.prototype.say = function () {
    return this.name;
};

function Child(name) {
    /**
     * 1>优点:可以获得父对象自身成员的真实副本,不会存在子对象意外覆盖父对象属性的风险。
     * 2>缺点:无法从原型中继承任何东西 ,它并不会为每个实例重新创建原型。
     */
    Parent.apply(this, arguments);
}

var child = new Child('kingChild');
console.log(child.say());    //Object #<Child> has no method 'say'

  3.类式继承模式#3 —— 借用和设置原型(调用了两次父构造)

function Parent(name) {
    this.name = name || 'king';
}
Parent.prototype.say = function () {
    return this.name;
};

function Child(name) {
    //1>先借用构造函数
    Parent.apply(this, arguments);
}
//2>设置子构造函数的原型使其指向父构造函数创建的新实例
Child.prototype = new Parent();

var child = new Child('kingChild');
console.log(child.say());    //kingChild

  4.类式继承模式#4 —— 共享原型

function Parent(name) {
    this.name = name || 'king';
}
Parent.prototype.say = function () {
    return this.name;
};

function Child(name) {
    this.name = name;
}
/**
 * 所以的对象实例实际上都共享了同一个原型。但是,这同时也是一个缺点,
 * 因为如果在继承链下方的某处存在一个子对象或者孙子对象修改了原型,它将会影响到所有的父对象和祖先对象。 
 */
function inherit(C, P) {
    C.prototype = P.prototype;
}
inherit(Child, Parent);

var child = new Child('kingChild');
console.log(child.say());    //kingChild

  5.类式继承模式#5 —— 临时构造函数

function Parent(name) {
    this.name = name || 'king';
}
Parent.prototype.say = function () {
    return this.name;
};

function Child(name) {}
/**
 * 这里的子对象仅仅继承了父对象的原型中的属性,这种方式是可取的,因为原型正是放置可复用功能的位置。
 * 在这种模式中,父构造函数添加到this中的任何成员都不会被继承。
 */
function inherit(C, P) {
    var F = function () {};
    F.prototype = P.prototype;
    C.prototype = new F();
}
inherit(Child, Parent);

var child = new Child('kingChild');
console.log(child.name);    //undefined
console.log(child.say);    //function () {...}

  

  类式继承模式 —— 总结

var inherit = (function () {
    /**
     * 应用闭包使得在每次需要继承时都创建临时(代理)构造函数。
     */
    var F = function () {};
    return function (C, P) {
        F.prototype = P.prototype;
        C.prototype = new F();
        /**
         * uber属性是指向超类的指针(不使用super仅仅是因为它是关键字),
         * 这就像在其他编程语言中访问超类一样,这可以偶尔排上用场。
         */
        C.uber = P.prototype;
        /**
         * 充值构造函数指针
         * 如果不充值该构造函数指针,那么所有子对象将会报告Parent()是它们的构造函数,这是没有任何用处的。
         * 重置constructor属性使其指向期望的构造函数且不会影响其功能,这是由于该属性主要是用于提供对象的信息。 
         */
        C.prototype.constructor = C;
    }
})();

  源自《JavaScript模式》