JavaScript中的继承是经过原型链实现的,有几种设计继承的方法总结以下:app
一. 原型链函数
基本思想:每一个构造函数都有一个原型对象,原型对象又都包含一个指向构造函数的指针,而实例又指向一个原型对象的指针,那么,若是咱们让原型对象等于另外一个类型的实例,此时的原型对象将包含一个指向另外一个原型的指针,相应的另外一个原型中也包含着一个指向另外一个构造函数的指针,假如另外一个原型又是另外一个类型的实例呢,那么上述的关系依然成立,如此层层递进,就构成了实例和原型的链条。下面是例子this
1 function SuperType(){ 2 this.property = true; 3 } 4 SuperType.prototype.getSuperValue = function(){ 5 return this.property; 6 } 7 function SubType(){ 8 this.subproperty = false; 9 } 10 //继承SuperType 11 SubType.prototype = new SuperType(); 12 SubType.prototype.getSubValue = function(){ 13 return this.subproperty; 14 }; 15 var instance = new SubType(); 16 alert(instace.getSuperValue());//true
缺点:引用类型值的属性会被全部实例共享,假设有两个子类型的实例,其中一个实例修改了从超类型继承而来的引用类型的值,修改的结果也一样会在另外一个实例中显示出来;spa
建立子类型的实例的时候,不能向超类型的构造函数中传递参数。prototype
二.借用构造函数设计
基本思想:在子类型构造函数的内部调用超类型构造函数,即经过apply和call方法来调用构造函数指针
1 function SuperType(){ 2 this.colors = ["red","blue","green"]; 3 } 4 function SubType(){ 5 //继承了SuperType 6 SuperType.call(this); 7 } 8 var instance1 = new SubType(); 9 instance1.colors.push("black"); 10 alert(instance1.colors);//"red,blue,green,black" 11 var instance2 = new SubType(); 12 alert(instance2.colors);//"red,blue,green"
优势:解决了原型中包含引用类型值所带来的问题code
缺点:超类型的原型中定义的方法,对子类型而言也是不可见的(没有指向超类型原型的指针,只有指向构造函数的),结果全部类型都只能使用构造函数模式,这样确定是很差的。对象
三.组合继承blog
基本思想:使用原型链实现对原型属性和方法的继承,经过借用构造函数来实现对实例属性的继承下面是例子
1 function SuperType(name){ 2 this.name = name; 3 this.colors = ["red","blue","green"]; 4 } 5 SuperType.prototype.sayName = function(){ 6 alert(this.name); 7 }; 8 function SubType(name,age){ 9 //继承属性 10 SuperType.call(this,name); 11 this.age = age; 12 } 13 //继承方法 14 SubType.prototype = new SuperType(); 15 SubType.prototype.constructor = SubType; 16 SubType.prototype.sayAge = function(){ 17 alert(this.age); 18 }; 19 var instance1 = new SubType("Nicholas",29); 20 instance1.colors.push("black"); 21 alert(instance1.colors);//"red,blue,green,black" 22 instance1.sayName();//"Nicholas" 23 instance1.sayAge();//29 24 var instance2 = new SubType("Greg",27); 25 alert(instance2.colors);//"red,blue,green" 26 instance2.sayName();//"Greg" 27 instance2.sayAge();//27
组合继承是最经常使用的继承模式,并且,利用instanceof 和isprototypeof()也可以用于识别基于组合继承建立的对象
四.原型式继承
基本思想:借助原型能够基于已有的对象建立新对象,同时,没必要所以建立自定义类型。下面是例子
1 function object(o){ 2 function F(){}; 3 F.prototype = o; 4 return new F(); 5 } 6 var person = { 7 name:"Nicholas", 8 friends:["shelby","Cour","Van"] 9 }; 10 var anotherPerson = object(person); 11 anotherPerson.name = "Greg"; 12 anotherPerson.friends.push("Rob"); 13 var yetAnotherPerson = object(person); 14 yetAnotherPerson.name = "Linda"; 15 yetAnotherPerson.friends.push("Barbie"); 16 alert(person.friends);//"Shelby,Court,Van,Rob,Barbie"
缺点:仍是包含引用类型值得属性始终会共享相应的值,实例中修改会在原型中展示。
不管什么状况下都会调用两次超类型构造函数:一次是在建立子类型原型的时候,另外一次是在子类型构造函数内部,子类型最后会包含超类型中的所有实例属性,但有时候咱们会在调用子类型构造函数时重写这些属性。
五.寄生式继承
基本思路:与寄生构造函数和工厂模式相似,即建立一个仅用于封装继承过程的函数,该函数在内部以某种方式类加强对象。下面是例子:
function object(o){ function F(){}; F.prototype = o; return new F(); } function createAnother(original){ var clone = object(original);//经过调用函数来建立一个新对象 clone.sayHi = function(){ alert("hi"); }; return clone; } var person = { name:"Nicholas", friends:["Shelby","Court","Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi();//"Hi"
使用场景:在主要考虑对象而不是自定义类型和构造函数的状况下。
六.寄生组合式继承
为了解决组合继承的缺点
基本思想:经过借用构造函数来继承属性,经过原型链的混成形式来继承方法
function object(o){ function F(){}; F.prototype = o; return new F(); } function inheritPrototype(subType,superType){ var prototype = object(superType.ptorotype);//建立对象 prototype.constructor = subType;//加强对象 subType.prototype = prototype;//指定对象 }
可以正常使用instanceof() 和 isPrototypeOf()。