構造函數或構造器具備prototype屬性 對象具備__proto__屬性 這就是以前學習的原型
若是構造函數或對象A A的原型指向構造函數或對象B B的原型在指向構造函數或對象C 以此類推 最終的構造函數或對象的原型指向Object的原型 由此造成一條鏈狀結構 被稱之爲原型鏈
按照上述的描述 在B中定義的屬性或方法 能夠直接在A中使用並不須要定義 這就是繼承 它容許每一個對象來訪問其原型鏈上的任何屬性或方法。
原型鏈是ECMAScript標準中指定的默認實現繼承方式。app
// 原型鏈 function A(){ this.a = 'a'; } // 經過構造函數建立對象 var a = new A(); function B(){ this.b = 'b'; } // 將B的原型指向對象a B.prototype = a; // 經過構造函數建立對象 var b = new B(); console.log(b.b);// b console.log(b.a);// a function C(){ this.c = 'c'; } // 將C的原型指向對象b C.prototype = b; // 經過構造函數建立對象 var c = new C(); console.log(c.c);// c console.log(c.b);// b console.log(c.a);// a
處於對效率的考慮,儘可能的將屬性和方法添加到原型上。
1.不要爲繼承關係單首創建對象。
2.儘可能減小運行時的方法搜索。函數
// 原型鏈 function A(){ // 將自有屬性改寫爲原型屬性 // this.a = 'a'; } A.prototype.a = 'a'; function B(){ // this.b = 'b'; } // 將B的原型指向 B.prototype = A.prototype; B.prototype.b = 'b'; /*B.prototype = { b : 'b' }*/ function C(){ this.c = 'c'; } // 將C的原型指向 C.prototype = B.prototype; var c = new C(); console.log(c.c);// c console.log(c.b); console.log(c.a);// a
原型鏈雖然很強大,用他能夠實現JavaScript中的繼承,但同時也存在着一些問題。
1.原型鏈實際上實在多個構造函數或對象之間共享屬性和方法。
2.常見子類的對象時,不能向父級的構造函數傳遞任何參數。
在實際開發中不多會單獨使用原型鏈。學習
// 原型鏈 function A(){ // 將自有屬性改寫爲原型屬性 // this.a = 'a'; } A.prototype.a = 'a'; function B(){ // this.b = 'b'; } // 將B的原型指向 B.prototype = A.prototype; B.prototype.b = 'b'; function C(){ // this.c = 'c'; } // 將C的原型指向 C.prototype = B.prototype; C.prototype.c = 'c'; var c = new C(); console.log(c.c);// c console.log(c.b);// b console.log(c.a);// a var a = new A(); console.log(a.a); console.log(a.b); console.log(a.c); var b = new B(); console.log(b.a); console.log(b.b); console.log(b.c);
所謂的原型式繼承,就是定義一個函數,該函數中建立一個臨時性 的構造函數,將做爲參數傳入的對象,做爲這個構造函數的原型,左後返回這個構造函數的實例對象。this
/* 定義一個函數 - 用於實現對象之間的繼承 * 參數 * obj - 表示繼承關係中的父級對象 * prop - 對象格式,表示繼承關係中的子級對象的屬性和方法 */ function fn(obj, porp){ // 定義一個臨時的構造函數 function Fun(){ // 遍歷對象的屬性和方法 for (var attrName in porp) { // var attrValue = porp[attrName]; this[attrName] = porp[attrName]; } } // 將函數的參數做爲構造函數的原型 Fun.prototype = obj; // 將構造函數建立的對象進行返回 return new Fun(); } var obj = { name : '張無忌' } // 調用函數 var result = fn(obj, { age : 18, sayMe : function(){ console.log('this is function'); } }); console.log(result.age); result.sayMe();
注意;原型式繼承具備與原型鏈相同的問題。prototype
不管是原型鏈仍是原型式繼承,都具備相同的問題。想要解決這樣的問題的話,能夠藉助構造函數(也能夠叫作僞造對象或經典繼承)。
這種方式實現很是簡單,就是在子對象的構造函數中調用父對象的構造函數,具體能夠經過調用apply()和call()方法實現。
apply()和call()方法容許傳遞指定某個對形象的 this。對於繼承來講,能夠實現子對象構造函數中調用父對象的構造函數時,將子對象的this和父對象的this綁定在一塊兒。code
// 定義父級對象的構造函數 function Parent(){ this.parent = 'parent'; } // 定義子級對象的構造函數 function Child(){ // 調用父級對象的構造函數 -> 使用apply()或call()方法 Parent.call(this); this.child = 'child'; } // 建立子級對象 var child = new Child(); console.log(child);
組合繼承,也佳做爲經典繼承,指的是將原型鏈或原型式繼承和藉助構造.函數的技術組合在一塊兒,發揮兩者長處的一種繼承方式。
1.使用原型鏈或原型式繼承實現對原型的屬性和方法的繼承。
2.經過藉助構造函數實現對實例對象的屬性和繼承。
這樣既經過在原型定義方法實現了函數的重用,又保證每一個對象都有本身的專有屬性。對象
function Parent(){ // 構造函數的自有屬性 this.name = '張無忌'; } // 構造函數的原型屬性 Parent.prototype.age = 18; function Child(){ // 繼承父級構造函數中的自有屬性 Parent.call(this); this.job = '教主'; } // 繼承父級構造函數中的原型屬性 Child.prototype = Parent.prototype; var child = new Child(); console.log(child.job); console.log(child.age); console.log(child.name);