面向面試編程——javascript繼承的6種方法
阿新 • • 發佈:2017-05-19
javascrip 復制 call bject object reat 常用 對象賦值 friends
javascript繼承的6種方法
1,原型鏈繼承
2,借用構造函數繼承
3,組合繼承(原型+借用構造)
4,原型式繼承
5,寄生式繼承
6,寄生組合式繼承
1.原型鏈繼承.
<script type="text/javascript"> function Person(name,sex) { this.name=name; this.sex=sex; this.friends=[‘李四‘]; this.getName=function(){ alert(this.name); } } Person.prototype.id=1; function Boy(age) { this.age=age; this.getAge=function(){ alert(this.age); } } //繼承 Boy.prototype=new Person("張三","男"); var boy=new Boy(16); alert(boy.name); //張三 boy.getAge(); //16 alert(boy.id); //1 //屬性共享問題 console.log(boy.friends); //李四 var boy2=new Boy(17); boy2.friends.push(‘王五‘); //修改boy2的friends屬性的同時也影響了boy的屬性 console.log(boy.friends); //李四 王五 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //true console.log(Person.prototype.isPrototypeOf(boy)); //true </script>
特點:既繼承了父類的模板,又繼承了父類的原型對象。
缺點:只能在父類設置一些參數,子類不能靈活傳參,不符合面向對象的思想,包含引用類型值的屬性始終都會共享相應的值。
2.借用構造函數繼承
<script type="text/javascript"> //父類 function Person(name,sex) { this.name=name; this.sex=sex; this.friends=[‘李四‘]; } Person.prototype.id=1; //子類 function Boy(name,sex,age) { //借用 Person.call(this,name,age); this.age=age; this.getAge=function(){ alert(this.age); } } var boy=new Boy("張三","男",16); alert(boy.name); //張三 boy.getAge(); //16 alert(boy.id); //undefined 沒有繼承父類的原型對象 //屬性共享問題 ————不會有共享 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
特點:只繼承了父類的模板,不繼承父類的原型對象。
缺點:方法都在構造函數中定義,不能做到函數復用。
3.組合繼承(原型+借用構造)最常用的繼承模式
<script type="text/javascript"> //父類 function Person(name,sex) { this.name=name; this.sex=sex; } Person.prototype.id=1; //子類 function Boy(name,sex,age) { //借用構造函數 繼承父類的模板 Person.call(this,name,age); this.age=age; this.getAge=function(){ alert(this.age); } } //不傳遞參數,繼承父類的模板,繼承父類的原型對象 id Boy.prototype=new Person(); var boy=new Boy("張三","男",16); alert(boy.name); //張三 boy.getAge(); //16 alert(boy.id); //1 //屬性共享問題 ————除了父類的原型對象,不會有共享 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //true console.log(Person.prototype.isPrototypeOf(boy)); //true </script>
特點:既繼承了父類的模板,又繼承了父類的原型對象。
缺點:做了3件事,繼承了父類兩次模板,繼承了一次原型對象
原型式繼承解決了這個問題
4.原型式繼承
<script type="text/javascript"> var person={ name:‘張三‘, sex:‘男‘, friends:[‘李四‘] } function object(obj) { function F(){} //創建一個空的構造函數 F.prototype=obj; //將傳入的對象作為這個構造函數的原型 return new F(); //返回一個新實例 對傳入的對象進行了一次淺復制 } var boy=object(person); //ECMAScript 5 新增了Object.create()方法 與本例 object 方法行為相同 //可改為 Object.create(person); alert(boy.name); //張三 //但是原型式同樣存在屬性共享的問題 //例如: var girl=object(person); girl.friends.push(‘王五‘); alert(boy.friends); //李四 王五 alert(girl.friends);//李四 王五 //修改girl中的friends屬性 boy 也會受到影響 //無法使用 instanceof 和 isPrototypeof </script>
創造的目的是基於已有的對象創建新的對象,同時還不必因此創建自定義類型。
包含引用類型值的屬性始終都會共享相應的值,就像使用原型模式一樣。
5.寄生式繼承
<script type="text/javascript"> function object(obj) { function F(){} //創建一個空的構造函數 F.prototype=obj; //將傳入的對象作為這個構造函數的原型 return new F(); //返回一個新實例 對傳入的對象進行了一次淺復制 } function Person(person) { var clone=object(person); clone.getSex=function(){ alert(this.sex); } return clone; } var person={ name:‘張三‘, sex:‘男‘, friends:[‘李四‘] } var boy=Person(person); boy.getSex(); //男 //屬性共享問題————因為傳入同一個實例,所以存在共享問題 var boy2=Person(person); boy2.friends.push(‘王五‘); alert(boy.friends); //李四 王五 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
與構造函數模式類似,不能做到函數復用會降低效率。
6.寄生組合式繼承
<script type="text/javascript"> function object(o) { function F(){} console.log(o); F.prototype=o; return new F(); } function extend(subType,superType) { var prototype=object(superType.prototype); //創建父類的一個副本 prototype.constructor=subType; //為創建的副本添加失去默認的構造函數 subType.prototype=prototype; //將新創建的對象賦值給子類的原型 } function Person(name) { this.name=name; this.friends=[‘李四‘]; } function Boy(name,sex) { Person.call(this,name); //借用構造函數 繼承父類的模板 this.sex=sex; } extend(Boy,Person); //繼承 var boy=new Boy(‘張三‘,‘男‘); alert(boy.name); //張三 //屬性共享問題————不會存在共享問題 var boy2=new Boy(‘張三‘,‘男‘); boy2.friends.push(‘王五‘); alert(boy.friends); //李四 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
寄生式組合繼承解決了組合繼承會調用兩次父類構造函數,子類最終會包含父類的全部實例屬性,父類的屬性不是必須的,子類的屬性會覆蓋父類的屬性。
寄生式組合繼承只調用一次父類構造函數,原型鏈能保持不變,因此還能夠正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生組合繼承,是實現基於類型繼承的最有效的方式。
面向面試編程——javascript繼承的6種方法