本文實例講述了JavaScript原型鏈與繼承操做。分享給你們供你們參考,具體以下:前端
1. JavaScript繼承程序員
JavaScript繼承能夠說是發生在對象與對象之間,而原型鏈則是實現繼承的主要方法;面試
1.1 原型鏈架構
利用原型讓一引用類型繼承另外一個引用類型的屬性和方法。app
構造函數中有個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(); //李四吃飯了
運行結果: this
注意:prototype
①:當 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.歡迎你們進羣交流討論,學習交流,共同進步。
當真正開始學習的時候不免不知道從哪入手,致使效率低下影響繼續學習的信心。
但最重要的是不知道哪些技術須要重點掌握,學習時頻繁踩坑,最終浪費大量時間,因此有有效資源仍是頗有必要的。
最後祝福全部遇到瓶疾且不知道怎麼辦的前端程序員們,祝福你們在日後的工做與面試中一切順利。