前言

关于继承,在ES 6 之前,只支持实现继承 ,且实现继承主要是依靠原型链继承,即使Class 的extends 也是基于原型继承(语法糖),下面的内容中会详细介绍,各位看官往下瞧

原型链继承

定义
  • 子类可以通过原型链的查找,实现父类的属性公用与子类的实例
  • 子类添加的新方法不能使用对象字面量的形式添加
缺点
  • 一些引用数据操作的时候会出问题,两个实例会公用继承实例的引用数据类
实现
function SuperType (){
  this.property = true;
  this.colors = ["red", "blue", "green"];
}

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
}

//对象字面量  会覆盖
// SubType.prototype = {
//   methodName() {
//   }
// }

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

var instance2 = new SubType();
instance2.colors.push("black");
console.log(instance1.colors)

复制代码

借用构造函数继承

定义
  • 在子类型构造函数的内部调用超类型构造函数 使用apply()或call 方法(不使用原型)
缺点
  • 只能继承父类的实例属性和方法,不能继承原型属性/方法
  • 无法实现复用,每个子类都有父类实例函数的副本,影响性能
实现
function SuperType (name){
  this.colors = ["red", "blue", "green"];
  this.name = name;
}

function SubType(){
  // 关键点 继承 SuperType 类 并传递了参数
  SuperType.call(this,'Nicholas')
  this.age = 23
}

var instance1 = new SubType();
instance1.colors.push("black");
var instance2 = new SubType();

console.log(instance1.colors)// ["red", "blue", "green", "black"]
console.log(instance2.colors)// ["red", "blue", "green"]

console.log(instance1.name) //Nicholas
console.log(instance1.age)  //23

复制代码

组合继承

定义
  • 用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。

  • 有时候也叫做伪经典继承

缺点
  • 调用两次超类型, 存在两份相同的属性/方法,实例和原型上各有一份
实现
function SuperType (name){
  this.colors = ["red", "blue", "green"];
  this.name = name;
}
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的constructor属性,指向自己的构造函数SubType 否自指向超类型
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
  console.log(this.age)
}

var instance1 = new SubType('小明',20);
instance1.colors.push("black");
console.log(instance1.colors)// ["red", "blue", "green", "black"]
instance1.sayAge() //20
instance1.sayName() // 小明

var instance2 = new SubType('小红',21);
console.log(instance2.colors)// ["red", "blue", "green"]
instance2.sayAge() //21
instance2.sayName() //小红

复制代码

原型式继承

定义

利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。

缺点
  • 不能做到函数复用
  • 共享引用类型属性的值
  • 无法传递参数
实现
function object(obj){
  function F(){}
  F.prototype = obj;
  return new F();
}

var person = {
  name: 'Nicholas',
  friends : ["Shelby","Coury","Van"]
}

var anotherPerson  = object(person)
// 与Object.create 相同 相比之下 Object.create更规范化 
// var anotherPerson  = Object.create(person) 
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
复制代码

寄生式继承

定义
  • 寄生式继承是与原型式继承继承紧密相关的一种思路
  • 在原型式继承的基础上,增强对象,返回构造函数
缺点(同原型式继承)
  • 不能做到函数复用
  • 共享引用类型属性的值
  • 无法传递参数
代码
 function createAnother(original){
  var clone = object(original); // 或 Object.create(original) 
  clone.sayHi = function(){  // 以某种方式来增强对象
    alert("hi");
  };
  return clone; // 返回这个对象
}


var person = {
  name: 'Nicholas',
  friends : ["Shelby","Coury","Van"]
}

var anotherPerson  = createAnother(person) 

anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = createAnother(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
复制代码

寄生组合式继承

定义
  • 结合借用构造函数传递参数和寄生模式实现继承
  • 通过借用构造函数继承属性,通过原型链的混成形式继承方法
  • 使用寄生式继承来继承超类型的原型,然后在将结果指定给子类型的原型
实现
  function inheritPrototype(subType, superType){
  var prototype =Object.create( superType.prototype); // 创建对象,创建父类原型的一个副本
  prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
  subType.prototype = prototype  // 指定对象,将新创建的对象赋值给子类的原型

}

// 父类初始化实例属性和原型属性
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;
}


// 将父类原型指向子类
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function (){
  alert(this.age)
}


var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);

instance1.colors.push("black"); // ["red", "blue", "green", "black"]
instance2.colors.push("gray"); // ["red", "blue", "green", "gray"]
复制代码

ES6类继承extends

定义
  • extends关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。
  • 一个类中只能有一个构造函数
  • Class 定义的方法 直接挂载到原型上
  • 子类没有自己的this对象,所以必须先调用父类的super()方法,否则新建实例报错。
实现
 class SuperType {
  constructor(name,age){
    this.age = age;
    this.mame = name;
  }

  
  getAge(){
    return this.age
  }

  getName(){
    return this.name
  }

}

class SubType extends  SuperType{
  constructor(name,age,sex){
    //调用超类型  必须在使用“this”之前首先调用 super()。
    super(name,age)
    this.sex = sex
  }
}

var instance = new SubType('渣渣辉',18,'男')

console.log(instance.getAge())
复制代码

结语

本文介绍的几种继承方式 ,基本足够日常开发使用了, 还有其他的继承方式在这里就先不介绍了. 在学习中,关于继承方面的知识尤为重要,希望大家好好学习,活学活用,争做大佬,向大佬们学习.嘿嘿 !!!
复制代码

参考文章 木易杨说,JavaScript常用八种继承方案

(前端界的一枚小学生)