溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

javascript中實現(xiàn)繼承的示例分析

發(fā)布時間:2022-02-19 14:17:43 來源:億速云 閱讀:144 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下javascript中實現(xiàn)繼承的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

類式繼承

//聲明父類
//聲明父類
function SuperClass() {
  this.superValue = true;
}
//為父類添加共有方法
SuperClass.prototype.getSuperValue = function () {
  return this.superValue;
};

//聲明子類
function SubClass() {
  this.subValue = false;
}

//繼承父類
SubClass.prototype = new SuperClass();
//為子類添加共有方法
SubClass.prototype.getSubValue = function () {
  return this.subValue;
};

var instance = new SubClass();
console.log(instance.getSuperValue()); //true
console.log(instance.getSubValue()); //false
類式繼承需要將父類的實例賦值給子類原型, subClass.prototype 繼承了 superClass。 這種類式繼承有兩個缺點。其一,由于子類通過原型 prototype 對父類實例化,繼承了父類,父類中的共有屬性要是引用類型,就會在子類中被所有實例共用,因此一個子類的實例更改子類原型從父類構(gòu)造函數(shù)中繼承來的共有屬性就會直接影響到其他子類,如下:
function SuperClass() {
    this.courses = ['語文', '數(shù)學(xué)', '英語']
}
function SubClass() {}
SubClass.prototype = new SuperClass();

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

console.log(instance2.courses) //['語文', '數(shù)學(xué)', '英語']
instance1.courses.push('化學(xué)')
console.log(instance2.courses) //['語文', '數(shù)學(xué)', '英語', '化學(xué)']
instance1 的修改直接影響了 instance2,這是一個災(zāi)難的陷阱。其二,由于子類實現(xiàn)的繼承是靠其原型 prototype 對父類的實例化實現(xiàn)的,因此在創(chuàng)建父類的時候,是無法向父類傳遞參數(shù)的,因而在實例化父類的時候也無法對父類構(gòu)造函數(shù)內(nèi)的屬性進行初始化。如何解決這個問題?請繼續(xù)往下看。

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

function SuperClass(current) {
  this.courses = ["語文", "數(shù)學(xué)", "英語"];
  this.current = current;
}

//父類聲明原型方法
SuperClass.prototype.getCourses= function () {
  console.log(this.courses);
};

//聲明子類
function SubClass(current) {
  SuperClass.call(this, current);
}

var instance1 = new SubClass("語文");
var instance2 = new SubClass("數(shù)學(xué)");

instance1.courses.push('化學(xué)')
console.log(instance1.courses); //["語文", "數(shù)學(xué)", "英語", "化學(xué)"]
console.log(instance1.current); //語文
console.log(instance2.courses); //["語文", "數(shù)學(xué)", "英語"]
console.log(instance2.current); //數(shù)學(xué)

instance1.getCourses() //TypeError: instance1.getCourses is not a function
SuperClass.call(this, current) 這條語句是構(gòu)造函數(shù)繼承的精華。由于 call 這個方法可以更改函數(shù)的作用環(huán)境,因此在子類中,對 SuperClass 調(diào)用這個 call 就是將子類中變量在父類中執(zhí)行一遍,由于父類中是給 this 綁定屬性的,因此子類也就繼承了父類的共有屬性。 由于這種類型的繼承沒有涉及原型 prototype,所以父類的的原型方法不會被子類繼承,要想被子類繼承,只能將 showCourse 放在父類構(gòu)造函數(shù)中,但是這樣就違背了代碼復(fù)用的原則。為了綜合以上兩種繼承的優(yōu)點,于是有了組合繼承。

組合繼承

//組合繼承

function SuperClass(current) {
  //引用類型共有屬性
  this.courses = ["語文", "數(shù)學(xué)", "英語"];
  // 值類型共有屬性
  this.current = current;
}

SuperClass.prototype.getCourses = function () {
  console.log(this.courses);
};

SuperClass.prototype.getCurrent = function () {
  console.log(this.current);
};

// 聲明子類
function SubClass(current, time) {
  //構(gòu)造函數(shù)繼承父類屬性
  SuperClass.call(this, current);
  this.time = time;
}
//類式繼承 子類原型繼承父類
SubClass.prototype = new SuperClass();
//子類原型方法
SubClass.prototype.getTime = function () {
  console.log(this.time);
};
在子類構(gòu)造函數(shù)中執(zhí)行父類構(gòu)造函數(shù),在子類的原型上實例化父類就是組合模式,子類實例中更改父類繼承下來的引用類型屬性 courses 不會改變其他實例,測試如下
var instance1 = new SubClass("語文", "9:00");
instance1.getTime(); //9:00
instance1.courses.push('化學(xué)')
instance1.getCourses(); //["語文", "數(shù)學(xué)", "英語", "化學(xué)"]
instance1.getCurrent(); //語文
console.log(instance1.current)//語文

var instance2 = new SubClass("數(shù)學(xué)", "10:00");
instance2.getTime(); //10:00
instance2.getCourses(); //["語文", "數(shù)學(xué)", "英語"]
instance2.getCurrent(); //數(shù)學(xué)
console.log(instance2.current)//數(shù)學(xué)
但是該模式在執(zhí)行子類構(gòu)造函數(shù)時執(zhí)行了一遍父類函數(shù),在實現(xiàn)子類原型繼承時又執(zhí)行了一遍父類構(gòu)造函數(shù),調(diào)用了父類構(gòu)造函數(shù)兩遍,顯然是一個設(shè)計缺陷,那還有更好的方式嗎?針對該缺陷,出現(xiàn)了“寄生組合式繼承”

寄生組合式繼承

在介紹這種繼承方式之前,需要先了解 “原型式繼承”和“寄生式繼承”

基礎(chǔ)了解

原型式繼承

function inheritObject(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var course = {
  name: "語文",
  alikeCourse: ["數(shù)學(xué)", "英語"],
};

var newCourse = inheritObject(course);
newCourse.name = "化學(xué)";
newCourse.alikeCourse.push("物理");

var otherCourse = inheritObject(course);
otherCourse.name = "政治";
otherCourse.alikeCourse.push("歷史");

console.log(newCourse.name); //化學(xué)
console.log(newCourse.alikeCourse); //["數(shù)學(xué)", "英語", "物理", "歷史"]

console.log(otherCourse.name); //政治
console.log(otherCourse.alikeCourse); //["數(shù)學(xué)", "英語", "物理", "歷史"]

console.log(course.name); //語文
console.log(course.alikeCourse); //["數(shù)學(xué)", "英語", "物理", "歷史"]
inheritObject 可以看做是對類式繼承的一種封裝,其中的過度類 F 相當(dāng)于類式繼承中的子類。在類式繼承中存在的共用引用類型的問題依然存在,但是過度類 F 構(gòu)造函數(shù)中無內(nèi)容,所以開銷較小。

寄生式繼承

“寄生式繼承”是在“原型式繼承”的基礎(chǔ)上繼續(xù)增強。
function inheritObject(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var course = {
  name: "語文",
  alikeCourse: ["數(shù)學(xué)", "英語"],
};

function createCourse(obj) {
  //通過原型繼承方式創(chuàng)建新對象
  var o = new inheritObject(obj);
  // 拓展新對象
  o.getName = function () {
    console.log(this.name);
  };
  return o;
}

const newCourse = createCourse(course)
這種方式在某個對象內(nèi)部持續(xù)增長屬性,像寄生式生長,所以稱之為寄生繼承。寄生繼承是對原型繼承的二次封裝,并且在二次封裝的過程中對繼承的對象做了拓展,這樣新創(chuàng)建的對象不僅僅有父類中的屬性和方法,而且還添加了新的屬性和方法。在這種思想的基礎(chǔ)上,結(jié)合組合式繼承,衍生了 “寄生組合式繼承”

實現(xiàn)

function inheritObject(o) {
    function F() {}
    F.prototype = o;
    return new F();
  }
function inheritPrototype(subClass, superClass) {
    //復(fù)制一份父類的原型副本保存在變量中
    var p = inheritObject(superClass.prototype)
    //修正因為重寫子類原型導(dǎo)致子類的constructor屬性被修改
    p.constructor = subClass
    //設(shè)置子類的原型
    subClass.prototype = p
}
以上父類原型保存一個副本,賦值給子類原型,從而實現(xiàn)繼承,且并未重新調(diào)用一次父類函數(shù),測試如下,與組合繼承模式相近
//test

function SuperClass(current) {
  //引用類型共有屬性
  this.courses = ["語文", "數(shù)學(xué)", "英語"];
  // 值類型共有屬性
  this.current = current;
}

SuperClass.prototype.getCourses = function () {
  console.log(this.courses);
};

SuperClass.prototype.getCurrent = function () {
  console.log(this.current);
};

// 聲明子類
function SubClass(current, time) {
  //構(gòu)造函數(shù)繼承父類屬性
  SuperClass.call(this, current);
  this.time = time;
}

//寄生式繼承 子類原型繼承父類
inheritPrototype(SubClass, SuperClass);

//類式繼承 子類原型繼承父類
// SubClass.prototype = new SuperClass();

//子類原型方法
SubClass.prototype.getTime = function () {
  console.log(this.time);
};

var instance1 = new SubClass("語文", "9:00");
var instance2 = new SubClass("數(shù)學(xué)", "10:00");

instance1.getTime(); //9:00
instance1.courses.push("化學(xué)");
instance1.getCourses(); //["語文", "數(shù)學(xué)", "英語", "化學(xué)"]
instance1.getCurrent(); //語文
console.log(instance1.current); //語文

instance2.getTime(); //10:00
instance2.getCourses(); //["語文", "數(shù)學(xué)", "英語"]
instance2.getCurrent(); //數(shù)學(xué)
console.log(instance2.current); //數(shù)學(xué)

區(qū)別僅在

//寄生式繼承 子類原型繼承父類
inheritPrototype(SubClass, SuperClass);

//類式繼承 子類原型繼承父類
// SubClass.prototype = new SuperClass();
從而實現(xiàn)多個子類多個實例不相互影響,父類構(gòu)造函數(shù)僅僅調(diào)用一次,堪當(dāng) JavaScript 繼承的終極模式。

看完了這篇文章,相信你對“javascript中實現(xiàn)繼承的示例分析”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI