面向?qū)ο缶幊蹋豪^承

1、類式繼承

第1步、聲明父類

function SuperClass() {
    this.superValue = true;
}

第2步、為父類添加共有方法

SuperClass.prototype.getSuperValue = function() {
    return this.superValue;
}

第3步、聲明子類

function SubClass() {
    this.subValue = false;
}

第4步、繼承父類,核心就是這一步,子類的原型指向第一個(gè)類的實(shí)例。

實(shí)例化父類的時(shí)候,實(shí)例對(duì)象復(fù)制父類構(gòu)造函數(shù)內(nèi)的屬性和方法,并且將__proto__指向了父類的原型對(duì)象,這樣就擁有了父類原型對(duì)象上的屬性和方法。

將實(shí)例對(duì)象賦值給子類的原型,子類就可以訪問(wèn)父類的屬性和方法。

SubClass.prototype = new SuperClass();

第5步、為子類添加共有方法

SubClass.prototype.getSubValue = function() {
    return this.subValue;
}

使用子類:

var instance = new SubClass();
console.log(instance.getSuperValue()); // true
console.log(instance.getSubValue()); // false

判斷類與實(shí)例的關(guān)系:

console.log(instance instanceof SuperClass); // true
console.log(instance instanceof SubClass); // true
console.log(SubClass instanceof SuperClass); // false 繼承關(guān)系,而不是類與實(shí)例的關(guān)系
console.log(SubClass.prototype instanceof SuperClass); // true

console.log(instance instanceof Object); // true 說(shuō)明所有對(duì)象也是Object的實(shí)例

缺陷一:子類的2個(gè)實(shí)例之間會(huì)互相影響

先科普一下,值類型有:字符串、數(shù)值、布爾值、null、undefined,特征是不可變。引用類型有:對(duì)象、數(shù)組、函數(shù),特征是可操作,可改變。

當(dāng)父類的共有屬性是引用類型,然后一個(gè)子類實(shí)例修改了父類的屬性值,那么任何指向引用類型的變量都會(huì)變,所以另一個(gè)子類實(shí)例的屬性也就變了。例如:

function SuperClass() {
    this.superValue = [true];
}

function SubClass() {}
SubClass.prototype = new SuperClass();

var instance1 = new SubClass();
var instance2 = new SubClass();

console.log(instance1.superValue); // [true]
instance1.superValue.push(8);
console.log(instance1.superValue); // [true, 8]
console.log(instance2.superValue); // [true, 8]

缺陷二:子類實(shí)例無(wú)法向父類傳遞參數(shù)

子類實(shí)例只能向子類傳遞參數(shù),沒(méi)有辦法向父類傳遞參數(shù)。不舉例了。

2、構(gòu)造函數(shù)繼承

構(gòu)造函數(shù)繼承,用的是傳說(shuō)中的.call或.apply方法。

// 第一步、聲明父類
function SuperClass(id) {
    // 引用類型共有屬性,這次再看看是否解決的上面的缺陷一
    this.books = ['JS', 'HTML5', 'CSS'];
    // 值類型共有屬性
    this.id = id;
}

// 第二步、父類型聲明原型方法
SuperClass.prototype.showBooks = function() {
    console.log(this.books);
};

// 第三步、聲明子類
function SubClass(id) {
    SuperClass.call(this, id); // 精華所在
}

// 第四步,創(chuàng)建兩個(gè)子類實(shí)例
var instance1 = new SubClass(1);
var instance2 = new SubClass(2);

// 使用和測(cè)試
instance1.books.push('PHP');
console.log(instance1.books); // ["JS", "HTML5", "CSS", "PHP"]
console.log(instance1.id); //1
console.log(instance2.books); // ["JS", "HTML5", "CSS"]
console.log(instance2.id); // 2

instance1.showBooks(); // TypeError

注意上面代碼中的“精華所在”,也就是call的用法。

可以看到子類內(nèi)部就一行代碼,就是SuperClass.call(this, id);,當(dāng)子類實(shí)例創(chuàng)建的時(shí)候,SuperClass.call(this, id)就被執(zhí)行了一遍。那么發(fā)生了什么呢?

第一步,將SuperClass函數(shù)的this綁定到this指向的對(duì)象上,也就是子類實(shí)例

第二步,給SuperClass函數(shù)傳參,傳遞的參數(shù)先是SuperClass函數(shù)自帶的參數(shù),然后依次是arg1, arg2, arg3...,這里是id,也就是子類的參數(shù)id傳給了父類,父類呢,又賦值給了this指向的對(duì)象(也就是子類實(shí)例)的id方法

第三步,執(zhí)行SuperClass函數(shù)。這樣一來(lái),父類就傳遞給子類實(shí)例方法和屬性。

缺陷:看到上面的TypeError吧,父類的原型方法,子類根本繼承不到,非要繼承則必須放到父類構(gòu)造函數(shù)里,但構(gòu)造函數(shù)的方法寫到構(gòu)造函數(shù)的里面不是最佳實(shí)踐,因?yàn)楦鱾€(gè)子類實(shí)例不能共用方法,浪費(fèi)內(nèi)存,所以,請(qǐng)看下面的組合繼承:

3、組合繼承

類式繼承,是通過(guò)實(shí)例化一個(gè)父類,然后賦值給子類的prototype來(lái)實(shí)現(xiàn)。

構(gòu)造函數(shù)式繼承,是通過(guò)在子類的構(gòu)造函數(shù)作用環(huán)境里,執(zhí)行了一次父類的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)的。

綜合上述兩點(diǎn),就構(gòu)成了組合繼承。

// 第一步、聲明父類,跟構(gòu)造函數(shù)式繼承一樣
function SuperClass(name) {
    // 引用類型共有屬性,這次再看看是否解決的上面的缺陷一
    this.books = ['JS', 'HTML5', 'CSS'];
    // 值類型共有屬性
    this.name = name;
}

// 第二步、父類聲明共有方法,也跟構(gòu)造函數(shù)式繼承一樣
SuperClass.prototype.getName = function() {
    console.log(this.name);
};

// 第三步、聲明子類
function SubClass(name, time) {
    SuperClass.call(this, name); // 這依然跟構(gòu)造函數(shù)式繼承一樣
    this.time = time; // 這跟類式繼承一樣
}

// 第四步,子類原型繼承父類,跟類式繼承一樣
SubClass.prototype = new SuperClass();

// 第五步,子類原型方法,跟類式繼承一樣
SubClass.prototype.getTime = function() {
    console.log(this.time);
}

// 使用和測(cè)試
var instance1 = new SubClass(1, 2015);
var instance2 = new SubClass(2, 2016);

instance1.books.push('PHP');
console.log(instance1.books); // ["JS", "HTML5", "CSS", "PHP"]
console.log(instance1.name); //1
console.log(instance1.time); //2015
console.log(instance2.books); // ["JS", "HTML5", "CSS"]
console.log(instance2.time); // 2016

缺陷:父類被調(diào)用了兩次,浪費(fèi)內(nèi)存。但是這是目前用得最多的繼承實(shí)現(xiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容