1.原型链继承
1.1
让对象obj2的原型指向obj1的实例。则说obj2继承了obj1,既obj2.prototype=new obj1( );
function obj1(){
this.property1=true;
}
obj1.prototype.sayObj1=function(){//方法定义在原型上
return this.property1;
}
function obj2(age){
this.property2=false;
}
//让obj2原型继承obj1,obj2的原型指向obj1的实例
obj2.prototype=new obj1();
//给obj2新定义一个方法
obj2.prototype.sayObj2=function(){
return this.property2;
}
//定义obj2的一个实例
var instance=new obj2();
console.log(instance.sayObj1());//true
对象创建的时候,实例的属性定义在构造函数中,方法定义在原型中。
最后一句,instance.sayObj1()的过程:首先会在obj2.prototype中查找,若没有找到,则继续在obj1.prototype中查找。
原因:instance是obj2的实例,其instance._proto_指向构造函数的原型既obj2.prototype,然后再obj2.prototype中没有找到,则继续查找obj2.prototype._proto_,因为obj2.prototype是obj1的一个实例,则obj2.prototype._proto_指向构造函数的原型既obj1.prototype。然后再obj1.prototype中找到了sayObj1.
注意:原型链的查找记住 实例的_proto_指向的是构造函数的原型(构造函数的prototype),实例与原型有关,与构造函数没有关系。
注意不要忘记默认的原型链:如下
1.2 怎样确定原型和实例的关系
instanceof操作符: instance instanceof Object
isPrototypeOf()方法:obj2.prototype.isPrototypeOf( instance)
1.3 谨慎的定义方法
顺序:先继承,后添加方法
function Obj1(){
this.property1=true;
}
obj1.prototype.sayObj1=function(){//方法定义在原型上
return this.property1;
}
function Obj2(age){
this.property2=false;
}
//让obj2原型继承obj1,obj2的原型指向obj1的实例
obj2.prototype=new obj1();
//给obj2添加新的方法
obj2.prototype.sayObj2=function(){
return this.property2;
}
//对obj2的方法进行了重写
obj2.prototype.sayObj1=function(){
return false;
}
//定义obj2的一个实例
var instance=new obj2();
var instance1=new obj1();
console.log(instance1.sayObj1());//true
console.log(instance.sayObj1());//false
注意:当obj2重新了方法的时候,obj2的实例在调用这个方法时调用的是重写后的方法;然而,obj1的实例在调用这个方法时,调用的还是以前的方法。
注意:使用原型链实现继承的时候,不能用对象字面量创建方法,会重写原型链。
如何避免原型链上的对象共享:
创建一个函数,这个函数里面使用空函数当做中间变量。
var a={name:'m'};
var b=cloneObj(a);
function cloneObj(obj){
var f=function(){}//空函数
f.prototype=obj;
return new f();
}
console.log(b.name);
2.构造函数实现继承
实现原理:在子类型中调用父类型的构造函数。使用call()方法或apply()方法都可以
function Parent(){
this.friend=["a","b"];
}
function child(){
//继承了parent
Parent.call(this);//将parent中的this绑定到了当前child中的this
}
var child1=new Parent();
child1.friend.push("c");
console.log(child1.friend)
构造函数继承相比原型继承最大的优点是,子类型在继承了父类型的时候还可以向父类型传递参数。
function Parent(name){
this.name=name;
}
function Child(){
//继承了parent的同时还传递了参数
Parent.call(this,"xiao");
this.age=29;
}
var child1=new Child();
console.log(child1.name);
console.log(child1.age)
问题:函数无法复用
3.组合继承
实现原理:使用原型链实现原型属性和方法的继承,使用构造函数实现实例属性的继承。
function Parent(name){
this.name=name;
this.colors=["a","b","c"];
}
Parent.prototype.sayName=function(){
return this.name;
}
function Child(name,age){
//继承父类型的属性,用构造函数继承
Parent.call(this,"xiao");
this.age=age;
}
//继承方法,用原型继承
Child.prototype=new Parent();//原型继承就把parent的方法就继承过来了
Child.prototype.constructor=Child;//再让child的原型指回child构造函数
Child.prototype.sayAge=function(){
return this.age;
}
var child1=new Child("shanshan",18);
4.原型式继承
实现:使用Object.create()方法。
var person={
name:"liss",
friends:["a","b","c"]
}
var anotherPerson=Object.create(person);
5.寄生式继承
//类似于工厂模式
function createAnother(original){//original参数是被继承的对象
var clone=object(original);//通过调用函数创建一个对象clone
clone.sayHi=function(){//以某种形式来增强这个对象
alert("hi");
};
return clone;
}
var person={
name:"liss",
friends:["a","b","c"]
}
var anotherPerson=createAnother(person);//继承了person对象
anotherPerson.sayHi();
问题:函数不能复用
6.寄生组合继承
寄生组合式继承的基本模式如下:
function inheritPrototype(parent,child){
var prototype=object(parent.prototype);//创建原型对象
prototype.constructor=child;//让原型对象的构造函数指向child
child.prototype=prototype;//让child的原型指向parent.prototype
}
function Parent(name){
this.name=name;
this.colors=["a","b"];
}
Parent.prototype.sayName=function(){
return this.name;
}
function Child(name,age){
Parent.call(this,"liss");
this.age=age;
}
inheritPrototype(Parent,Child);
Child.prototype.sayAge=function(){
return this.age;
}
优点:只使用了次parent的构造函数。引用类型最理想的继承范式。