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()。