一:接口继承
接口继承只继承方法签名,由于js函数没有签名,所以无法实现接口继承
二:实现继承
二-一:实现继承则继续实际的方法。
二-二:实现原理:
主要是依靠原型链来实现的。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
二-三 :原型链
二-三-一:实现原型链的基本模式
function SuperType(){ this.prototype=true; } SuperType.prototype.getSuperValue=function(){ return this.prototype; }; function SubType(){ this.Subprototype=false; }//继承了SuperType SubType.prototype=new SuperType(); //创建了SuperType的实例,并将该实例赋给SubType.prototype来实现的。 SubType.prototype.getSubValue=function(){ return this.subproperty; }; var instance=new SubType(); alert(instance.getSuperValue());//true 它们的主要区别是SubType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的
二-三-二:原型链的本质
实现的本质是重写原型对象,代之以一个新类型的实例。
简要概括就是子类有了[[Prototype]]指向父类的原型对象。
二-三-三:原型链扩展了原型搜索机制:
当以读取模式访问一个属性时,首先会 在实例中搜索该属性,如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上,直到原型链的末端 null;
二-三-四:默认的原型Object
继承了Object的所有属性和方法
二-三-五:不能用对象字面立法,会重写原型链
function SuperType(name) { this.name=true; } SuperType.prototype.getSuperType = function() { return this.name; } function SubType(name){ this.name=false; } //将SuperType的实例赋给了SubType的原型对象,实现了继承 SubType.prototype=new SuperType(); SubType.prototype={ getSubType:function(){ return this.name; }, some:function(){ return false; } } var sub=new SubType(); alert(sub.getSuperType());//error //由于现在的原型包含的是一个Object的实例,而非SuperType的实例,因此预想的原型链已经切断,SubType和SuperType之间已经没有关系了。
二-三-六:谨慎的定义方法
必须在用Supertype的实例替换原型之后,再定义这2个方法。
function SuperType(name) { this.name=true; } SuperType.prototype.getSuperType = function() { return this.name; } function SubType(name){ this.name=false; } //继承了SuperType SubType.prototype=new SuperType(); //添加新方法 SubType.prototype.getSubType=function(){ return this.name; } //重写超类型中的方法,将会屏蔽同名方法。 SubType.prototype.getSuperType = function() { return false; } var sub=new SubType(); alert(sub.getSuperType());//false
二-三-七:原型链的2个问题
1>最主要的问题来自包含引用类型值的原型
包含引用类型值的原型属性会被所有实例共享, 可以通过借用构造函数模式(伪造对象或经典继承)来解决:
1.1借用构造函数的思想:
通过apply()和call()在子类型构造函数的内部调用超类型构造函数,==>在新SubType对象上执行SuperType()函数中定义的所有对象初始化代码,这样SubType的每个实例就都会具有自己的colors属性的副本了。
function SuperType(){ this.color=["black","blue","red"]; } function SubType(){ //继承SuperType SuperType.call(this); } var sub=new SubType(); sub.color.push("yellow") alert(sub.color);//black,blue,red,yellow var sup=new SubType(); alert(sup.color);black,blue,red
1.2借用构造函数的优势
可以在子类型构造函数中向超类型构造函数中传递参数
function SuperType(name){ this.name=name; } function SubType(){ //继承SuperType SuperType.call(this,"mike"); this.age=29; } var sub=new SubType(); alert(sub.name);//mike alert(sub.age);//29
1.3借用构造函数的问题
1>存在着构造函数的问题,方法都在构造函数中定义,因此函数复用就无从谈起了。
2>在超类型中的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。
2>不能向超类型的构造函数中传递参数
在创建子类型的实例时,不能向超类型的构造函数中传递参数,实际上是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数
二-四:组合继承(伪经典继承)
基本思想:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
实现了函数的复用,又能保证每个实例都有它自己的属性。
function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name,age) { //继承SuperType SuperType.call(this, name); this.age = age; } SubType.prototype=new SuperType(); SubType.prototype.constructor=SubType; SubType.prototype.sayAge=function () { alert(this.age); } var sub=new SubType("mike",29); sub.colors.push("black"); alert(sub.colors);//red,blue,green,black sub.sayAge();//29 sub.sayName();//mike var sub2=new SubType("greg",27); alert(sub2.colors);//red,blue,green sub2.sayAge();//27 sub2.sayName();//greg