js中的继承主要使用原型链实现
原型链继承:利用原型让一个引用类型继承另一个引用类型的属性和方法
原型链:当查找一个实例属性时,先在实例中查找,找到就直接返回,找不到在沿着原型链向上查找直到原型链的末端,找到就返回,没找到就报错
- 原型链继承:缺点,子类的constructor也指向父类;共享(原来的原型实例属性会变成现在的原型属性),比如引用实例,所有一个实例对它进行操作时,其他实例也会相应变化;创建子类实例时,不能向超类的构造函数中传递参数
function superType(){
this.it= true;
}
superType.prototype.getSuperValue = function(){
return this.it
}
function subType(){
this.subIt = false;
}
subType.prototype = new superType();//sub继承super,子类的原型指向父类的实例,实现的本质是重写原型对象
subType.prototype.getSubValue = function(){
return this.subIt;
}
var ins = new SubType();
alert(ins.getSuperValue);//true;调用了父类方法
确定原型与实例的关系可以使用instanceof操作符和isPrototypeOf();方法,子类需要重写父类中的某个方法或者需要添加父类中某个不存在的方法,给原型添加代码的方法一定要放在替换原型的语句之后。在通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链
- 借用构造函数(伪造对象/经典继承):在子类的内部调用超类的构造方法
function SuperType(name){
this.name = name;
this.colors = ["red","blue"];
}
function SubType(){
SuperType.call(this,"xiaoxiao");//通过call或apply来在新创建的对象上执行构造函数
this.age = 29;
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red,blue,black"
var instance2 = new SubType();
console.log(instance2.colors);//"red,blue"
缺点:方法在构造函数中定义,函数无法复用
- 组合继承(伪经典继承),将原型链和借用构造函数的技术组合到一起,使用原型链实现对原型属性和方法的继承,通过调用构造函数来实现对实例属性的继承
function SuperType(name){
this.name = name;
this.colors = ["red","blue"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);//第二次调用父类函数
this.age = age;
}
SubType.prototype = new SuperType();//第一次调用父类函数
SubType.prototype.constructor = SubType;//让子类的constructor重新指向子类
SubType.prototype.sayAge = function(){
alert(this.age);
}
var one = new SubType("xiaoxiao",29);
one.colors.push("black");
alert(one.colors);//"red","blue","black"
one.sayName();//"xiaoxiao"
one.sayAge();//29
var two = new SubType("zhan",27);
alert(one.colors);//"red","blue"
one.sayName();//"zhan",
one.sayAge();//27
instanceof和isPrototypeOf()能够用于识别基于组合继承创建的对象
- 原型式继承:借助原型基于已有的对象创建新对象
function object(o){
Function F(){
F.prototype = o;
return new F();
}
}
var obj = {
name: "xs",
friends:["x","y"]
}
var p = object(obj);//obj的friends属性会被实例共享
var p2 = object(obj);
p2.name = "cd";
p2.fridens.push("u");
ES5新增了Object.create()方法规范原型式继承,接受两个参数,参1:用作新对象原型的对象和(可选的)一个为新对象额外定义额外的属性对象,在传入一个参数的情况下,与上面object()方法行为相同,第二个参数与Object.defineProperties()方法的格式相同
var per = {
name:"mkh";
};
var anp = Object.create(per,{
name:{
value:"Grey";
}
});
- 寄生式继承:创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再像真的是它做了所有工作一样的返回对象
例:
function createAnthor(orgin){
var clone = object(orgin);
clone.sayHi = function(){
alert("hi");
};
return clone;
}
var obj = {
name:"ey";
}
var anthor = createAnthor(obj);
anthor.sayHi();
- 寄生组合式继承:借用构造函数来继承属性,通过原型链的混成形式来继承方法
组合继承最大的问题是无论在什么情况下,都会调用两次超类的构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数内部
function inheritPrototype(sub,super){
var p = object(super.prototype);//创建对象
p.constructor = sub;//增强对象
sub.prototype = p;//指定对象
}
function SuperType(name){
this.name = name;
this.colors = ["red","blue"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);//第二次调用父类函数
this.age = age;
}
/*SubType.prototype = new SuperType();//第一次调用父类函数
SubType.prototype.constructor = SubType;//让子类的constructor重新指向子类
*/
inheritPrototype(SubType,SuperType);//替换上两个语句
SubType.prototype.sayAge = function(){
alert(this.age);
}