JS继承方式
原型链继承
利用原型链让一个引用类型继承另一个引用类型的属性和方法
function SuperType () { this.colors = ["red","blue","green"]; } function SubType () { } //SubType 继承 SuperType SubType.prototype = new SuperType (); var instance1 = new SubType (); instance1.colors.push ("black"); console.log (instance1.colors);//Array(4) ["red", "blue", "green", "black"] var instance2 = new SubType (); console.log (instance2.colors);//Array(4) ["red", "blue", "green", "black"]
本质是重写原型对象。instance指向SubType的原型,SubType原型指向SuperType原型。SuperType包含一个数组(引用类型值)。
缺点:包含引用类型值得原型属性会被所有实例共享。在创建子类型的实例时,不能向超类型的构造函数中传递参数。
借用构造函数
在子类型构造函数的内部调用超类型构造函数,通过call()或apply()方法在新建对象上执行构造函数。
function SuperType (name) { this.name = name; } function SubType () { SuperType.call (this,"John"); this.age = 22; } var instance = new SubType (); console.log (instance.name);//John console.log (instance.age);//22
缺点:无法实现函数复用
组合继承
使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。
function SuperType (name) { this.name = name; this.colors = ["red","black","green"] } SuperType.prototype.sayName = function () { console.log (this.name); } function SubType (name,age) { //继承属性 SuperType.call (this,name); //第二次调用SuperType() this.age = age; } //继承方法 SubType.prototype = new SuperType (); //第一次调用SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function () { console.log (this.age); } var instance1 = new SubType ("John",22); instance1.colors.push ("yellow"); console.log (instance1.colors);//Array(4) ["red", "black", "green", "yellow"] instance1.sayName ();//John instance1.sayAge ();//22 var instance2 = new SubType ("Amy",20); console.log (instance2.colors);//Array(3) ["red", "black", "green"] instance2.sayName ();//Amy instance2.sayAge ();//20
instance1和instance2既有自己的属性,又有相同的方法,是最常用的继承方式
缺点:调用两次超类型构造函数
原型式继承
将一个函数对象传递给object()得到一个新的实例对象,再根据需求对新对象进行修改
function object (o) { function F () {} F.prototype = o; return new F (); } var person = { name: "John", friends: ["A","B","C"] } var anotherPerson = object (person); anotherPerson.name = "Jack"; anotherPerson.friends.push ("D"); console.log (person.friends);//Array(4) ["A", "B", "C", "D"]
也可通过Object.create()方法规范原型式继承,传入一个参数时与object()相同
var person = { name: "John", friends: ["A","B","C"] } var anotherPerson = Object.create (person); anotherPerson.name = "Jack"; anotherPerson.friends.push ("D"); console.log (person.friends);//Array(4) ["A", "B", "C", "D"]
第二个参数制定的任何属性都会覆盖原型对象上的同名属性
var person = { name: "John", friends: ["A","B","C"] } var anotherPerson = Object.create (person,{ name: { value: "Amy" } }); console.log (anotherPerson.name);//Amy
寄生式继承
创建一个仅用于封装继承过程的函数
function object (o) { function F () {} F.prototype = o; return new F (); } function createAnother (original) { var clone = object (original); clone.sayhi = function () { console.log ("hi"); } return clone; } var person = { name: "John", friends: ["A","B","C"] } var anotherPerson = createAnother (person); anotherPerson.sayhi ();//hi
缺点:无法实现函数复用
寄生组合式继承
集寄生式继承和组合继承有点于一身,使用寄生式继承来继承超类型的原型,再将结果指定给子类型的原型。
function object (o) { function F () {} F.prototype = o; return new F (); } function inheritPrototype (subType,superType) { var prototype = object (superType.prototype); //创建对象 prototype.constructor = subType; //增强对象 subType.prototype = prototype; //指定对象, => subType.prototype = superType } function SubType (name) { this.name = name; this.colors = ["yellow","red"]; } SuperType.prototype.sayName = function () { console.log (this.name); }; function SubType (name,age) { SuperType.call (this,name); //调用SuperType() this.age = age; } inheritPrototype (SubType,SuperType); SubType.prototype.sayAge = function () { console.log (this.age); }
高效率只调用一次SuperType(),原型链保持不变,能正常使用instance和isPrototypeOf()。是实现基于引用类型继承最有效的方式。