盗用构造函数

476 阅读3分钟

这是我参与11月更文挑战的第29天,活动详情查看:2021最后一次更文挑战

前言

今天我们来讲一讲盗用的构造函数吧。

盗用构造函数

为了解决原型包含引用值导致的继承问题,一种叫作 “盗用构造函数”( constructor stealing )的技术在开发社区流行起来(这种技术有时也称作“对象伪装”或“经典继承”)。基本思路很简单:在子类构造函数中调用父类构造函数。因为毕竟函数就是在特定上下文中执行代码的简单对象,所以可以使用apply()和call()方法以新创建的对象为上下文执行构造函数。来看下面的例子:

function SuperType(){

this.colors = ["red""blue""green"];

function SubType ()//继承SuperType

SuperType .call(this);

let instance1 = new SubType() ;

instancel .colors.push("black") ;

console. log(instance1.colors) ; // "red, blue,green, black"

let instance2 = new SubType() ;

console. log (instance2.colors) ; // "red, blue, green"

示例中加粗的代码展示了盜用构造函数的调用。通过使用call()(或app1y() )方法,SuperType构造函数在为SubType的实例创建的新对象的上下文中执行了。这相当于新的SubType对象上运行了SuperType ()函数中的所有初始化代码。结果就是每个实例都会有自己的colors属性。

传递参数

相比于使用原型链,盗用构造函数的一个优点就是 可以在子类构造函数中向父类构造函数传参。来看下面的例子:

function SuperType (name){

this .name = name;

function SubType() {

//继承SuperType并传参

SuperType.call(this"Nicholas");

//实例属性

this.age = 29;

let instance = new SubType();

consolelog(instance .name); // "Nicholas";

consolelog(instance,age); //29

在这个例子中,SuperType构造函数接收一个参数name,然后将它赋值给一个属性。 在SubType构造函数中调用superype构造函数时传人这个参数,实际上会在SubType的实例,上定义name属性。为确保SuperType构造函数不会覆盖Subrype定义的属性,可以在调用父类构造函数之后再给子类实例添加额外的属性。

盗用构造函数的问题

盗用构造两数的主要缺点,也是使用构造函数模式自定义类型的问题:必须在构造函数中定义方法, 因此函数不能重用。此外,子类也不能访问父类原型上定义的方法,因此所有类型只能使用构造函数模式。由于存在这些问题,盗用构造函数基本上也不能单独使用。

组合继承

组合继承(有时候也叫伪经典继承)综合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。来看下面的例子:

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;

//继承方法

SubType.prototype = new SuperType() ;

SubType . prototype. sayAge = function() {


console. log(this.age) ;

);

let instancel = new SubType ("Nicholas"29;

instance1.colors.push("black") ;

console.log (instancel.colors) 
// "red, blue, green, black"instance1. sayName() ;

// "Nicholas" ;

instance1.sayAge() ;

// 29

let instance2 = new SubType("Greg"27);

console.log (instance2.colors); // "red, blue, green"instance2.sayName() ;

/ /"Greg";

instance2.sayAge() ;

// 27

在这个例子中,SuperType 构造函数定义了两个属性,name 和colors,而它的原型上也定义了一个 方法叫sayName ()。SubType构造函数调用了SuperType构造函数,传入了name参数,然后又定义了自己的属性age。此外,SubType . prototype也被赋值为SuperType的实例。原型赋值之后,又在这个原型上添加了新方法sayAge()。这样,就可以创建两个SubType实例,让这两个实例都有自己的属性,包括colors,同时还共享相同的方法。 组合继承弥补了原型链和盗用构造函数的不足,是JavaScript中使用最多的继承模式。而目组合继承也保留了instanceof操作符和isPrototypeOf()方法识别合成对象的能力。