JavaScript面向對象編程——繼承

原型鏈

原型鏈是什麼

構造函數或構造器具備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);
相關文章
相關標籤/搜索