標籤:pre UI 自訂 原型 修改 efi 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種方法