Appearance
寄生组合式继承
本节目标:理解“寄生组合式继承”的核心思路,并能把它用于实际开发或面试表达。 思路:
- 对于父类实例非共享属性,我们通过构造器借用的方式复制;
- 所以,设置子类原型时不必调用超类的构造函数创建超类实例,因为超类实例的非共享属性,会用构造器借用的方式来复制;
- 所以我们只要子类原型对象原型式继承父类原型对象即可;
- 这样子类实例即有了父类实例的非共享属性,又通过原型链继承得到了父类实例的共享属性。
寄生组合式继承的基本模式如下:参数为两个构造函数 function inheritPrototype(subType, superType) { //1.创建超类原型的一个副本 var prototype = object(superType.prototype); //2.将副本的constructor属性指向子类构造函数 // 可以为原型添加其它属性和方法 prototype.constructor = subType; //3.将子类的原型指向我们创建的副本 subType.prototype = prototype; }
具体实现如下:
- 先定义两个构造函数,其中子类构造函数借用父类构造函数,并在执行父类构造函数后,添加子类实例特有的属性;
- 再执行寄生组合式继承;
- 再为子类原型添加属性或方法;
执行过程:
- 子类原型对象原型式继承父类原型对象;
- 定义子类原型对象特有的属性或方法;
- 使用new创建子类实例,在子类执行环境下执行父类构造函数;
- 定义子类实例特有的属性和方法
function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType(name, age) { SuperType.call(this.name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function () { console.log(age); }
这个例子的高效率体现在:
- 它只调用了一次SuperType构造函数;
- 且避免了在SubType.prototype上面创建不必要的,多余的属性。
- 与此同时,原型链还能保持不变;因此还能够正常使用instanceof 和isPrototypeOf。
开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。 YUI的YAHOO.lang.extend()方法采用了寄生组合式继承,从而让这种模式首次出现在了一个应用非常广泛的Javascript库中。
寄生组合式继承(Parasitic Combination Inheritance)是 JavaScript 中一种非常有效和实用的继承方式,它结合了构造函数继承和原型链继承的优点,同时避免了组合继承的一些缺点。它通过使用寄生式继承来减少重复调用父类构造函数,从而提高性能和内存利用率。
实现方法 寄生组合式继承的关键在于以下几点:
- 通过构造函数继承父类的实例属性。
- 通过寄生式继承继承父类的原型属性。
示例代码 下面是一个使用寄生组合式继承实现继承的示例: // 父类构造函数 function Parent(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } // 父类原型方法 Parent.prototype.sayName = function() { console.log(this.name); }; // 子类构造函数 function Child(name, age) { Parent.call(this, name); // 继承父类属性 this.age = age; } // 寄生式继承父类原型 function inheritPrototype(child, parent) { let prototype = Object.create(parent.prototype); // 创建父类原型的副本 prototype.constructor = child; // 修正 constructor 指向 child.prototype = prototype; // 将副本赋值给子类原型 } inheritPrototype(Child, Parent); Child.prototype.sayAge = function() { console.log(this.age); }; // 测试寄生组合式继承 let instance1 = new Child('Alice', 25); instance1.colors.push('black'); console.log(instance1.colors); // 输出: ['red', 'blue', 'green', 'black'] instance1.sayName(); // 输出: Alice instance1.sayAge(); // 输出: 25 let instance2 = new Child('Bob', 30); console.log(instance2.colors); // 输出: ['red', 'blue', 'green'] instance2.sayName(); // 输出: Bob instance2.sayAge(); // 输出: 30
详细解释
- 构造函数继承:
- 在子类构造函数 Child 中,使用 Parent.call(this, name) 调用父类构造函数,继承父类的实例属性。
- 寄生式继承父类原型:
- 使用 Object.create(parent.prototype) 创建父类原型的副本。
- 修正副本的 constructor 指向子类构造函数。
- 将这个副本赋值给子类的原型。
- 修复构造函数指向:
- 由于寄生式继承会创建一个新的对象副本,所以需要修正这个副本的 constructor 属性指向子类构造函数。
优点
- 性能优化:避免了在子类原型上直接创建父类实例的重复调用,减少了不必要的性能开销。
- 原型链共享:通过原型链共享方法,实现了高效的原型继承。
- 独立的实例属性:每个子类实例都有自己的属性副本,不会共享父类的实例属性,避免了引用类型属性共享问题。
缺点 复杂性:实现过程稍显复杂,需要理解 JavaScript 的原型链机制和构造函数调用。
总结 寄生组合式继承是一种结合了构造函数继承和原型链继承优点的高级继承方式。它在性能和内存利用率上表现优异,是实现 JavaScript 面向对象编程的理想选择。通过合理使用寄生组合式继承,可以构建出高效、可维护的继承结构。
