原型链
使某个原型对象成为另一个类型的实例,该原型对象将包含一个指向另一个原型的指针,如此层层递进,就构成了实例与原型的链条
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//继承
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
- 当子类型需要覆盖超类型中的某个方法或添加超类型没有的方法时,给原型添加的方法的代码一定要放在替换原型的语句之后
- 通过原型链实现继承时,不能使用对象字面量的方式创建原型方法,否则会重写原型,从而切断了原型链
- 不足:包含引用类型值的原型会被所有实例共享
关系如下:
原型搜索机制:首先在实例中搜索该属性,如果没有找到,则会继续在实例的原型中搜索,若还未找到,则在原型链实现继承的情况下,会继续向上搜索原型对象的原型对象,直达搜索到原型链的末端。
所有引用类型都默认继承了Oject对象,因此所有默认原型的__proto__
属性都会指向Object.prototype。关于__proto__
、prototype、constructor的关系,以及js中所有对象都继承于Object这点可以用这张图说明
- 实例对象是构造函数创建的,实例对象的
__proto__
属性指向其原型对象,构造函数的prototype指向原型对象,原型对象的constructor指向构造函数 - 构造函数也是实例对象,其是由function这个构造函数创建的,同时function的原型对象(
function.prototype
)也是对象,其是由Object这个构造函数创造的,原型对象是Object.prototype。换句话说,即function.prototype.__proto__等于Object.prototype
更详细的讲解,请参考这篇博客,这张图也是引用他的 https://www.cnblogs.com/xiaohuochai/p/5721552.html
借用构造函数
为解决原型链中引用值类型共享及参数传递问题,在子类型的构造函数的内部调用超类型的构造函数
function SuperType(name){
this.name = name;
}
function SubType(){
SuperType.call(this,"zjw"); //执行超类的构造函数,传入SubType的环境对象和参数,
//执行代码后,name属性就创建在了SubType的实例上
this.age = 28;
}
var instance = new SubType();
alert(instance.name) //"zjw"
alert(instance.age) //28
- 不足:构造函数无法解决函数复用问题,每次都要重新创造实例方法
组合继承
将原型链和借用构造函数组合到一块,使用原型链实现对原型属性和方法的继承,而构造函数实现对实例属性的继承
function SuperType(name){ //超类的构造函数
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){ //给超类的原型添加方法
alert(this.name);
};
function SubType(name,age){ //子类的构造函数
SuperType.call(this,name); //调用超类的构造函数,使每个实例都具有colors属性的副本
//从而没有直接继承超类的引用型属性
this.age = age;
}
SubType.prototype = new SuperType(); //继承超类
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){ //给子类的原型添加方法
alert(this.age);
};
var instance1 = new SubType("zjw",29); //创建子类型
instance1.colors.push("black");
alert(instance1.colors); //"red","blue","green","black"
instance1.sayName(); //"zjw"
instance1.sayAge(); //29
var instance2 = new SubType("bob",27);
alert(instance1.colors); //"red","blue","green"
instance1.sayName(); //"bob"
instance1.sayAge(); //27
原型式继承
基于已有对象创建新对象(浅复制,引用类型属性仍然共享)
直接使用Object.create()
方法,接受两个参数:要复制的对象和新添属性的对象
var anotherPerson = Object.create(Person,{
name:{
value:"zjw"
}
});
寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象,与工厂模式类似
function createAnother(o){
var clone = object(o) //创建新对象
clone.sayHi = function(){ //添加新方法
alert("hi");
}
return clone; //返回新对象
}
var person = {name:"zjw"};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //hi
- 跟构造函数一样不能做到函数复用
寄生组合式继承
解决传统的组合继承调用两次超类型构造函数问题,该方法用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function inheritProperty(SubType,SuperType){
var prototype = object(SuperType.prototype); //创建超类原型的副本
SubType.prototype = prototype; //继承超类副本
SubType.prototype.constructor = SubType; //弥补重写原型而丢失的constructor属性
}
function SuperType(name){ //超类的构造函数
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name,age){ //子类的构造函数
SuperType.call(this,name);
this.age = age;
}
inheritProperty(SubType,SuperType); //调用自定义的继承函数
SubType.prototype.sayAge = function(){
alert(this.age);
};
- 其避免了
SubType.prototype = new SuperType();
调用超类的构造函数 - 该种继承模式最有效,结合了组合继承和寄生式继承的优点