JS高程-6-3:继承

文章为《JavaScript高级程序设计》(第三版)笔记。

两种继承方式:接口继承和实现继承。接口继承只继承方法签名,实现继承则继承实际的方法。ECMAScript只支持实现继承,主要依靠原型链来实现

一.原型链

ECMAScript中将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在此之前,我们有必要搞清楚构造函数、原型和实例的关系:

详细可见:前端面试:原型链类

看个例子:

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

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

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

// 实现继承
SubType.prototype = new SuperType();

// 添加新方法(注:需要放在继承之后,不然会被覆盖。当然,也不能以字面量的形式修改原型,否则继承无效)
SubType.prototype.getSubValue = function() {
  return this.subproperty;
};

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

实现继承的本质是重写原型对象,代之一个新类型的实例

我们再看看子类SubType的prototype,实例instance在控制台中的输出:

我们发现,实例instance的原型链中确实有父类的属性与方法。

1.原型链的问题

问题一:引用类型值共享的问题

例子:

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

function SubType() {
}

// 继承
SubType.prototype = new SuperType();

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

var instance2 = new SubType();
alert(instance2.colors); // ['red', 'blue', 'green', 'black']

问题二:在创建子类型的实例时,不能向超类型的构造函数中传递参数

基于上述两个问题,导致我们在实践中很少会单独使用原型链来实现继承。

二.借用构造函数

借用构造函数的思想:在子类型构造函数的内部调用超类型构造函数。别忘了,函数只不过是在特定环境中执行代码的对象,因此通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数。 

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

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


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

var instance2 = new SubType();
alert(instance2.colors); // ['red', 'blue', 'green']

我们在创建SubType实例时,调用了SuperType构造函数,所以,SubType实例都具有自己的colors属性副本。

1.传递参数

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

function SubType() {
  // 继承
  SuperType.call(this, 'Tom');

  // 实例属性
  this.age = 2;
}


var instance = new SubType();
alert(instance.name); // "Tom"
alert(instance.age);  // 2

2.借用构造函数的问题

在超类型的原型中定义的方法,对子类型而言是不可见的,结果所有类型都只能使用构造函数模式。而使用构造函数模式存在一个问题——每个方法都要在实例上重新创建一遍。所以,借用构造函数的技术也是很少单独使用的。

三.组合继承

组合继承,又叫伪经典继承,是JavaScript中最常用的继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

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

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

function SubType(name, age) {
  // 继承属性
  SuperType.call(this, name);

  this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();

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

var instance1 = new SubType('Tom', 3);
instance1.colors.push('black');
alert(instance1.colors); // ['red', 'blue', 'green', 'black']
instance1.sayName(); // "Tom"
instance1.sayAge(); // 3

var instance2 = new SubType('Jerry', 2);
alert(instance2.colors); // ['red', 'blue', 'green']
instance2.sayName(); // "Jerry"
instance2.sayAge(); // 2

四.原型式继承

五.寄生式继承

六.寄生组合式继承

暂不介绍

猜你喜欢

转载自blog.csdn.net/qq_39025670/article/details/105823726
6-3
今日推荐