关于JavaScript继承的几种方法

前言

继承是JavaScript面向对象编程非常重要的一个特性,基本在日常使用以及面试过程中都会使用到。查阅一些资料后整理以下几种继承的方法记录在自己的博客中。

如何实现继承

原型链继承

原型链继承是最简单的一种继承方式,只需要将子类的prototype值等于父类的实例即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Animal(){
this.superType = 'Animal'
}
Animal.prototype.getSuperType = function(){
console.log(this.superType);
}
function Cat(name){
this.name = name;
this.type = 'Cat';
}
// 原型继承
Cat.prototype = new Animal();

var cat = new Cat()

cat.getSuperType(); // 控制台输出Animal

以上代码是将Animal的实例覆盖Cat的原型,本质是重写原型对象,代之一个新类型的实例。使Cat拥有Animal实例的所有属性和方法(getSuperType为原型方法),并且还有个指针指向了Animal的原型。当创建Cat的实例cat时,cat指向的是Cat的原型,Cat的原型又指向Animal的原型。

缺点

  • 引用类型值的原型属性会被共享
  • 在创建子类型的实例时,无法向超类型的构造函数传递参数

构造函数继承

借用构造函数继承也是非常简单地一种继承方式,即在子类构造函数的内部调用父类型构造函数。代码实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function(){
console.log(this.name);
}
function Cat(){
Animal.call(this, "cat");
this.eat = "fish"
}

var instance = new Cat();
console.log(instance.name);
console.log(instance.eat); // 控制台相继输出 cat fish
instance.getName() // error getName undefined

以上代码中的 Animal 只接受一个参数 name ,该参数会直接赋给一个属性。在 Cat 构造函数内部调用 Animal 构造函数时,实际上视为 Cat 的实例设置了 name 属性。为了确保 Animal 构造函数不会重写子类的属性,可以在调用父类构造函数后,再添加应该在子类型中定义的属性。

优点

  • 引用类型的原型属性不会被共享
  • 可以在子类型构造函数中向父类构造函数传递参数

缺点

  • 方法都在构造函数中定义,函数无法复用
  • 在父类的原型定义的方法,对子类型是不可见,导致所有的类型都只能使用构造函数

组合继承

原型式继承

寄生式继承

寄生组合式继承