实现继承的方法:
一,原型链:利用原型让一个引用类型继承另一个引用类型的属性和方法
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function(){ return this.property; }; function SubType(){ this.subproperty=false; } //继承了SuperType SubType.prototype=new SuperType(); SubType.prototype.getSubValue=function(){ return this.subproperty; } var instance=new SubType(); alert(instance.getSuperValue()); //true
注意问题:
a:所有引用类型默认都继承了Object,也是通过原型链实现的,所有函数的默认原型都是Object的实例。
alert(instance instanceof Object); //true
b:确定原型和实例之间的关系,可以用instanceof操作符和isPrototypeOf()方法。
实例与原型链中出现过的构造函数都会返回true。
alert(instance instanceof SubType); //true
原型链中出现过的原型,都可以说是原型链派生的实例的原型,返回true。
alert(SubType.prototype.isPrototypeOf(instance)); //true
c:给原型添加方法的代码一定要放在替换原型的语句之后。
d:通过原型链实现继承时不能使用对象字面量创建原型的方法,这样会重写原型链,之前的原型链被切断,SubType和SuperType之间没有关系了。
e:原型链的问题:每个实例都会共享属性,子类型不能向超类型中传参
优点:实例的方法可以共享
缺点:所有实例的属性共享
二,借用构造函数:在子类的构造函数内部调用超类型构造函数
function SuperType(){ this.colors=["red","blue","green"];//该数组就是引用类型值 } function SubType(){ //继承了SuperType SuperType.call(this);//SuperType.call(this)的意思就是使用SuperType 对象代替this对象,那么Subtype中不就有SuperType的所有属性和方法了,instance1对象就能够直接调用SuperType的方法以及属性了 } var instance1=new SubType(); instance1.colors.push("black"); alert(instance1.colors); //red,blue,green,black var instance2=new SubType(); alert(instance2.colors);//red,blue,green
a:可以传递参数
b:借用构造函数问题:方法都在构造函数中定义,因此所有函数无法复用
优点:解决了原型链实现继承属性共享的问题,可以传递参数
缺点:函数无法复用,每个实例的方法都不相同
三,组合继承:将原型链和借用构造函数的技术组合到一块,扬长补短,思想:使用原型链对原型属性和方法的继承,使用借用构造函数实现对实例属性的继承。
function SuperType(name){ this.colors=["red","green","blue"]; this.name=name; } //用原生链的方式将方法写在外面,让每个实例使用相同的方法 SuperType.prototype.sayName=function(){ alert(this.name); }; function SubType(name,age){ //第二次调用SuperType() SuperType.call(this,name); //让每个实例分别拥有自己的属性 this.age=age; } //继承方法 SubType.prototype=new SuperType(); //第一次调用SuperType() //弥补因重写原型而失去的默认的constructor属性 SubType.prototype.constructor=SubType; SubType.prototype.sayAge=function(){ alert(this.age); }; var instance1=new SubType("jane",29); instance1.colors.push("black"); alert(instance1.colors); //red,green,blue,black instance1.sayName(); //jane instance1.sayAge(); //29 var instance2=new SubType("tom",30); alert(instance2.colors);//red,green,blue instance2.sayName(); //tom instance2.sayAge(); //30 alert(instance1.sayName==instance2.sayName); //true alert(SubType.prototype.constructor==SubType);//true
优点:最常用的继承模式,解决了借用构造函数,函数不能复用的问题,以及原型链属性共享,以及不能传参的问题
缺点:如代码中所说,调用了两次超类型构造函数,如果删除instance2的colors属性,依然会返回red,green,blue,这样就无法删除colors属性
delete instance2.colors; alert(instance2.colors);//red,green,blue
四,原型式继承:基于已有的对象创建新对象
Object.create()方法实现原型式继承:
//传入一个参数的情况下,对象名 var person={ name:"jane", friends:["tom","nike","van"] }; var anotherPerson=Object.create(person); anotherPerson.name="greg"; anotherPerson.friends.push("rob"); var yetAnotherPerson=Object.create(person); yetAnotherPerson.name="linda"; yetAnotherPerson.friends.push("barbie"); alert(person.friends); //tom,nike,van,rob,barbie*
//Object.create()方法传入两个参数,第一个参数,对象名,第二个参数:属性都是通过自己的描述符定义的。 var person={ name:"jane", friends:["tom","nike","van"] }; var anotherPerson=Object.create(person, { //以这种方式指定的任何属性都会覆盖原型对象上的同名属性。 name:{ value:"greg" } } ); alert(anotherPerson.name); //greg
优点:不用再创建自定义的类型了
缺点:引用类型值的属性都会共享相应的值
五,寄生式继承:封装继承过程的函数
//createAnother函数接收了一个参数,也就是将要作为新对象基础的对象。 function createAnother(original){ //把original对象传递给Object函数,将返回的结果赋给clone var clone=Object(original); //再为clone对象添加一个方法 clone.sayHi=function(){ alert("hi"); }; return clone;//返回这个对象 } var person={ name:"jane", friends:["tom","nike","van"] }; var anotherPerson=createAnother(person); anotherPerson.sayHi();//hi anotherPerson具有Person不具有的方法sayHi()
优点:为对象添加函数
缺点:函数无法复用
六,寄生组合式继承:使用寄生式继承超类型的原型,再将结果返回给子类型的原型。
function inheritPrototype(SubType,SuperType){ var prototype=Object(SuperType.prototype);//创建对象 prototype.constructor=SubType; //弥补因重写原型而失去的默认的constructor属性 SubType.prototype=prototype;//指定对象 } function SuperType(name){ this.name=name; this.colors=["red","green","blue"]; } 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 instence=new SubType("jane",29); instence.sayName(); instence.sayAge();
优点:解决了组合继承的两次调用超类型构造函数问题