JavaScript原型鏈與繼承操作例項總結
本文例項講述了JavaScript原型鏈與繼承操作。分享給大家供大家參考,具體如下:
1. JavaScript繼承
JavaScript繼承可以說是發生在物件與物件之間,而原型鏈則是實現繼承的主要方法;
1.1 原型鏈
利用原型讓一引用型別繼承另一個引用型別的屬性和方法。
建構函式中有個prototype(每個函式中都有),指向他的原型物件,每個原型物件中也有一個constructor屬性,指向原建構函式。通過建構函式建立的新物件中都有一個無法直接訪問的[[proto]]屬性,使得物件也指向建構函式的原型。這使得物件也獲得了原型中的方法和屬性。
當訪問物件中的屬性或方法時,如果物件中沒有該屬性或方法,則會向上一級原型物件中尋找該屬性或方法,如果找了,就返回該屬性,若沒有則繼續向上面的原型中去查詢該屬性。
1.2 建構函式的原型鏈繼承
function Father(name,age){ this.name=name; this.age=age; } Father.prototype.eat=function(){ //給原型新增eat方法 console.log(this.name+"吃飯了"); } var f1=new Father("李四",20); //建立新物件f1, [[proto]]指向父原型 function Son(){ } Son.prototype=f1; //將子建構函式的prototype指向了父型別的物件,這裡實現了——繼承 var s1=new Son(); // 建立子物件 s1.eat(); //李四吃飯了
執行結果:
注意:
①:當 Son.prototype指向Father的時候,他就已經是父型別的Son了。
②:s1.eat();s1中沒有此方法,該方法在父型別原型中,當s1訪問時,現在s1中查詢,若沒有則向他指向的原型中去查詢該方法,若還是沒有,則繼續往上面的原型中查詢。這樣就形成了一條原型鏈。
③:通過原型鏈實現了繼承。
簡寫:
var f1=new Father;
var Son.prototype=f1
//可以直接簡寫成:
var Son.prototypr=new Father(); //這個時候可以傳值進去 ,其餘地方無法傳值
1.3 預設頂端原型
預設的頂端原型:
是當所有型別都沒有指明繼承某個型別時,則預設繼承Object型別。
objec中也有prototype指向他的object原型,object中也有[[proto]],只不過他指向的是null;可忽略。
object的很多方法,都是存在object的原型中;
在原型鏈中查詢,從當前位置一直往上訪問,直到原型鏈頂端位置。
1.4 測試資料
typeof 測資料的型別,最好只來測試基本型別資料,應為除了基本型別外全是返回object。
console.log(typeof 123) //number
console.log(typeof "ccsa ") //string
instnaceof 測試一個物件屬不屬於其父類物件的型別
function Father(name){
}
var f1=new Father();
console.log(f1 instanceof Father); //true
執行結果:
isPrototypeOf(要測的物件) 專屬於原型物件的方法,判斷該物件在不在該原型鏈上,使用:父類建構函式.prototype.isPrototypeOf(物件)
function Father(){
}
function Son(){
}
Son.prototype=new Father;
var s1=new son();
console.log(Father.prototype.isPrototypeOf(s1)); //true
console.log(Object.prototype.isPrototypeOf(s1)); //true
1.5 借調
借調:借用建構函式呼叫冒充繼承,借調實現的繼承,不是真正的繼承,只是借用建構函式中的屬性或方法。
apply,call。
function Fn(name,age){
this.name=name;
this.age=20;
}
function Son(name,age,sex){
Fn.call(this,name,age) //借調繼承Fn;
this.sex=sex;
};
var s1=new Son("李四",20,"男");
console.log(s1);
注意:借調缺點:call是冒充繼承,不是真正的繼承,所以不能訪問原建構函式的原型中的屬性或方法。
1.6 組合繼承
組合建構函式的借調繼承和原型的繼承優點:
function Fn(name,age){
this.name=name; //建構函式的屬性多樣
this.age=age;
if((typeof Fn.prototype.eat)!="funciton"){ //判斷語句中是否有該方法,沒有則建立
Fn.prototype.eat=function(){ //原型的方法共享
console.log(this.name+"吃了飯");
}
}
}
function Son(name,age,sex){ //建立子類建構函式
Fn.call(this,name,age) //借調Fn()的屬性
this.sex=sex;
};
Son.prototype=new Fn(); //Son.prototype指向父類物件,實現了繼承,所以能夠呼叫eat方法,
var s1=new Son("李四",20,"男"); //若沒有繼承,單單的使用call借調Fn繼承,子類例項s1無法呼叫eat方法
callconsole.log(s1); //因為call不是真正的繼承
s1.eat();
注意:Son.prototype=new Fn(); 這條語句 實現了Son繼承父型別Fn;Son指向的是父型別建立的物件,而父型別的物件有自己的屬性,並且又成為了子型別的原型,那麼其中的屬性不就成了共享的了嗎。 但是前面還有用到Fn.call( ),這條語句已經借調了父類建構函式屬性,相當於覆蓋了子型別原型的屬性。
最後
為了幫助大家讓學習變得輕鬆、高效,給大家免費分享一大批資料,幫助大家在成為全棧工程師,乃至架構師的路上披荊斬棘。在這裡給大家推薦一個前端全棧學習交流圈:866109386.歡迎大家進群交流討論,學習交流,共同進步。
當真正開始學習的時候難免不知道從哪入手,導致效率低下影響繼續學習的信心。
但最重要的是不知道哪些技術需要重點掌握,學習時頻繁踩坑,最終浪費大量時間,所以有有效資源還是很有必要的。
最後祝福所有遇到瓶疾且不知道怎麼辦的前端程式設計師們,祝福大家在往後的工作與面試中一切順利。