◆

JavaScript 继承详解:原型链继承等实现方式

2023-02-02 01:370

原型链继承

构造函数、原型和实例之间的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个原型对象的指针。

继承的本质就是复制,即重写原型对象,代之以一个新类型的实例。

function SuperType() {
  this.property = true;
}

SuperType.prototype.getSuperValue = function () {
  return this.property;
};

function SubType() {
  this.subproperty = false;
}

// 这里是关键,创建SuperType的实例,并将该实例赋值给SubType.prototype
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
  return this.subproperty;
};

var instance = new SubType();
console.log(instance.getSuperValue()); // true

存在的缺点:多个实例对引用类型的操作会被篡改。

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

function SubType() {}

SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // ['red', 'blue', 'green', 'black']

var instance2 = new SubType();
instance1.colors.shift();
console.log(instance2.colors); // ['blue', 'green', 'black']

构造函数的继承

使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类(不使用原型)

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

function SubType() {
  // 继承自SuperType
  SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push('black');
console.log('instance1.colors:', instance1.colors); // ['red', 'green', 'blue', 'black']

var instance2 = new SubType();
console.log('instance2.colors:', instance2.colors); // ['red', 'green', 'blue']
instance1.colors.shift();
console.log('instance1.colors:', instance1.colors); // ['green', 'blue', 'black']
console.log('instance2.colors:', instance2.colors); // ['red', 'green', 'blue']

核心代码是 SuperType.call(this),创建子类实例时调用 SuperType 构造函数,于是 SubType 的每个实例都会将 SuperType 中的属性复制一份。 缺点:

  • 只能继承父类的实例属性和方法,不能继承原型属性/方法
  • 无法实现复用,每个子类都有父类实例函数的副本,影响性能

组合继承

组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。

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

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

function SubType(name, age) {
  // 继承属性
  // 第二次调用SuperType()
  SuperType.call(this, name);
  this.age = age;
}

// 继承方法
// 构建原型链
// 第一次调用SuperType()
SubType.prototype = new SuperType();
// 重写SubType.prototype的constructor属性,指向自己的构造函数SubType
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
  alert(this.age);
};

var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black');
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType('Greg', 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVEJavaScript 继承详解:原型链继承等实现方式加载中