Skip to main content

js的六种继承模式

前言#

JS中的六种模式,基本的东西应该掌握。

1.原型链继承#

操作:将子类的原型赋值为父类的一个实例。
优点:子类的实例可以继承父类的原型链
缺点:所有子类的实例共享一份数据,不能向父类传参。

function superType() {  this.name = "rain";  this.hobbies = ["reading", "running"];}
function subType(age) {  this.age = age;}
//将子类的原型赋值为父类的一个实例subType.prototype = new superType();
var sub1 = new subType(18);var sub2 = new subType(19);sub1.name;  //rainsub1.hobbies.push("playing"); //["reading", "running", "playing"]sub2.name;  //rainsub2.hobbies; //["reading", "running", "playing"]

2.构造函数继承#

操作:在子类的函数中使用call来调用父类的构造函数
特点:子类中每个实例都有一份父类构造函数中数据
缺点:

  1. 只能继承构造函数内的数据,无法继承原型链中的数据
  2. 无法实现构造函数的复用
  3. 每个新实例都有父类构造函数的副本
function superType() {  this.name = "rain";  this.hobbies = ["reading", "running"];}superType.prototype.showName = function() {  console.log("My name is " + this.name);}
function subType(age) {  superType.call(this);   //将父类的构造函数在子类中调用  this.age = age;}
var sub1 = new subType(18);var sub2 = new subType(19);sub1.hobbies.push("playing");sub1.hobbies; //["reading", "running", "playing"]sub2.hobbies; //["reading", "running"]sub1.showName();  //报错,因为没有继承父类的原型链

3.组合式继承#

操作:将子类的原型赋值为父类的一个实例,在子类的构造函数中使用call调用父类的构造函数
特点:每个子类都有一份独立的数据,也可以继承父类的原型链。
缺点:要调用两次父类的构造函数,子类原型中,即那个父类的实例中的数据是多余的。因为子类的实例中有相同的属性,会将原型中的同名属性屏蔽。

function superType() {  this.name = "rain";  this.hobbies = ["reading", "running"];}superType.prototype.showName = function() {  console.log("My name is " + this.name);}
function subType(age) {  superType.call(this);   //将父类的构造函数在子类中调用  this.age = age;}subType.prototype = new superType();subType.prototype.constructor = subType;

4.原型式继承#

操作:构建一个空函数,令空函数的原型为目标对象,返回空函数的实例。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:

  1. 所有实例都会继承原型上的属性
  2. 无法实现复用。
function object(obj) {  function f() {};  f.prototype = obj;  return new f();}
var sup = new superType();var sub = new object(sup);

5.寄生式继承#

操作:寄生式继承模式,是在原型式继承的基础上,添加别的属性或方法。添加的属性在实例中。
优点:没有创建自定义类型,因为只是套了个壳子返回对象。这个函数就成了新的对象。
缺点:做不到函数复用。每次使用寄生函数新增实例时,都会为实例赋予一个新的函数。

//父类function superType() {  this.name = "rain";  this.hobbies = ["reading", "running"];}//父类原型添加的方法superType.prototype.showName = function() {  console.log("My name is " + this.name);}//原型式继承工具函数function object(obj) {  function f() {};  f.prototype = obj;  return new f();}//寄生式继承增强方法function paraObject() {  var sup = new superType();  var sub = object(sup);  sub.age = 18;  sub.showAge = function() {    console.log("my age is " + this.age);  }  return sub;}
var a = new paraObject();a.age;  //18a.showAge();  //my age is 18

6.寄生组合式继承#

其实就是组合式继承的改良版。组合式继承是子类是构造函数的原型是父类的一个实例。而寄生式则是:先使用类似Object.create()的方法获得继承了父类原型的一个实例,构造函数指向父类的构造函数,再将其作为子类构造函数的原型。

这样就解决了组合式继承的问题:子类构造函数的原型是父类的一个实例,原型中的数据会被子类实例中同名数据屏蔽。

function superType() {  this.name = "rain";  this.hobbies = ["reading", "running"];}superType.prototype.showName = function() {  console.log("My name is " + this.name);}
function subType(age) {  superType.call(this);   //将父类的构造函数在子类中调用  this.age = age;}//原型式继承工具函数function object(obj) {  function f() {};  f.prototype = obj;  return new f();}
function inheritPrototype(subType, superType) {  var prototype = object(superType.prototype);  //获得一个干净的父类原型  prototype.constructor = subType;  //将原型的构造函数设置为子类  subType.prototype = prototype;  //子类的原型设置为父类的原型}

总结#

开发中比较常用的是组合式继承和寄生组合式继承。最好的继承方式是寄生组合式继承。
因为js的原型链特性,对于所谓的”继承“,其实就是需要考虑函数的复用,组合。前面几种的继承模式有不同的缺陷,添加某些操作修复缺陷后,就变为了一种新的继承方式。

2019.12.16 大雪
written by LRQ