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来调用父类的构造函数
特点:子类中每个实例都有一份父类构造函数中数据
缺点:
- 只能继承构造函数内的数据,无法继承原型链中的数据
- 无法实现构造函数的复用
- 每个新实例都有父类构造函数的副本
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()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:
- 所有实例都会继承原型上的属性
- 无法实现复用。
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