一. 前言:
?? Hello,大家最近過得好嗎,😃,函式繼承是在JS里比較基礎也是比較重要的一部分,而且也是面試中常常要問到的,下面帶你快速了解JS中有哪幾種是經常出現且必須掌握的繼承方式,掌握下面的內容面試也差不多沒問題啦~
?? 當然,這需要一定的原型鏈基礎,對原型鏈不熟悉的可以看我這篇文章👉:速識js原型鏈,
二.原型鏈繼承:
?原型鏈繼承的要點在于父類的實體作為子類的原型,直接看下面這個例子:
// 父函式 Person
function Person(name, age) {
// 定義一些屬性
this.name = name;
this.age = age;
this.nature = ["auroras", "wind", "moon"];
}
// 定義Person原型上的一個方法
Person.prototype.sayLove = function () {
console.log(this.name + " like " + this.nature[0]);
};
// 子函式 Jack
function Jack() {}
// 父類的實體作為子類的原型 (-------------------實作核心--------------------------)
Jack.prototype = new Person();
現在我們創建兩個Jack 的實體,測驗看是否實作了繼承Person:
var jack1 = new Jack();
var jack2 = new Jack();
jack2.nature[0] = "sea";
jack1.sayLove();
jack2.sayLove();
console.log(jack1.nature);
console.log(jack2.nature);
?看運行結果確實繼承了,能執行sayLove方法,但有甚多缺點,創建Jack實體的時候傳遞不了引數name和age,而且不同實體間nature參考型別屬性相互影響,一個改變那都改變:

三.借用建構式繼承(物件偽裝):
?核心在于“盜用建構式”(constructor stealing),在子類建構式中呼叫父類建構式,因為畢竟函式就是在特定背景關系中執行代碼的簡單物件,所以可以使用apply()和call()方法以新創建的物件為背景關系執行建構式,它能解決原型鏈繼承中傳引數和參考型別屬性沖突,還是直接看例子:
// 父函式 Person
function Person(name, age) {
// 定義一些屬性
this.name = name;
this.age = age;
this.nature = ["auroras", "wind", "moon"];
}
// 定義Person原型上的一個方法
Person.prototype.sayLove = function () {
console.log(this.name + " like " + this.nature[0]);
};
// 子函式 Lucy
function Lucy(name, age) {
// 通過call把this指向Lucy,相當于拷貝了一份父函式 Person 里的內容(---------實作核心--------------)
Person.call(this, name, age);
}
//給子函式原型上也定義一個方法
Lucy.prototype.syaName = function () {
console.log("My name is " + this.name);
};
現在我們創建兩個Lucy 的實體,測驗看是否實作了繼承Person:
var lucy1 = new Lucy("lucy1", "20");
var lucy2 = new Lucy("lucy2", "22");
lucy2.nature[0] = "sea";
console.log(lucy1.name);
console.log(lucy1.nature);
console.log(lucy2.nature);
lucy1.syaName();
lucy2.syaName();
lucy1.sayLove();
?結果看可以繼承了,能傳引數,參考型別屬性也不互相影響,但是缺點顯而易見,可以看到報錯,無法使用父類的原型上的方法sayLove,

四.組合繼承:
?組合繼承就是結合了原型鏈繼承和借用建構式繼承兩者的核心實作的一種繼承方法,既能傳遞引數,參考型別屬性也互不影響,同時子類也能獲取得到父類的方法,這也是目前比較常用的繼承方式,直接看例子:
// 父函式 Person
function Person(name, age) {
// 定義一些屬性
this.name = name;
this.age = age;
this.nature = ["auroras", "wind", "moon"];
}
// 定義Person原型上的一個方法
Person.prototype.sayLove = function () {
console.log(this.name + " like " + this.nature[0]);
};
// 子函式Lisa
function Lisa(name, age) {
// 通過call把this指向Lisa,相當于拷貝了一份父函式 Person 里的內容(------實作核心-----------)
Person.call(this, name, age);
}
// 父類的實體作為子類的原型 (--------------實作核心-------------------)
Lisa.prototype = new Person();
//小知識點,這里是讓Lisa的constructor重新指向Lisa,不然因為Lisa的原型為Person實體,constructor會指向Person
Lisa.prototype.constructor = Lisa;
現在我們創建兩個Lisa 的實體,測驗看是否實作了繼承Person:
var lisa1 = new Lisa("lisa1", "20");
var lisa2 = new Lisa("lisa2", "21");
lisa2.nature[0] = "sea";
console.log(lisa1.name);
console.log(lisa1.nature);
console.log(lisa2.nature);
lisa1.sayLove();
lisa2.sayLove();
?可以看到基本上實作了我們繼承的功能,也修補了原型鏈和借用建構式繼承的缺點,但是呢,它還是有一個小缺點,就是可以看到在代碼注釋實作核心那,兩次都呼叫了Person,那么Lisa原型上和實體上有了兩份相同的屬性,那就會多少有一些性能浪費,

五.寄生組合繼承:
? 其實寄生組合繼承和組合繼承差不多的,就是多了一個解決組合繼承上原型和實體產生兩份相同屬性的缺點,解決核心是我們既然只是想要子類原型賦值為父類原型,那沒必要new一個父類實體,直接創造一個新物件,它值為父類的原型,再將它賦值給子類原型就行了,
? 其中用到Object.create(proto,[propertiesObject])這個方法創建一個新物件,相當于新物件的__proto__為其引數proto,當然Object.create可能低版本ie沒有,所以下面也自定義封裝了Object.create方法,當然只是簡單封裝,直接看例子:
// 父函式 Person
function Person(name, age) {
// 定義一些屬性
this.name = name;
this.age = age;
this.nature = ["auroras", "wind", "moon"];
}
// 定義Person原型上的一個方法
Person.prototype.sayLove = function () {
console.log(this.name + " like " + this.nature[0]);
};
// 子函式 Andy
function Andy(name, age) {
Person.call(this, name, age);
}
// 如果沒有 Object.create()方法,簡單封裝下
if (!Object.create) {
Object.create = function (proto) {
function Temp() {}
Temp.prototype = proto;
return new Temp();
};
}
// 呼叫Object.create方法,新建一對像,其__proto__為Person.prototype,并賦值給 Andy.prototype (-------實作核心----------)
Andy.prototype = Object.create(Person.prototype);
//修改constructor指向
Andy.prototype.constructor = Andy;
現在我們創建兩個Andy的實體,測驗看是否實作了繼承Person:
console.log(Andy.prototype.__proto__ === Person.prototype);
var andy1 = new Andy("andy1", "20");
var andy2 = new Andy("andy2", "21");
andy2.nature[0] = "sea";
console.log(andy1.name);
console.log(andy1.nature);
console.log(andy2.nature);
andy1.sayLove();
andy2.sayLove();
完美運行:

六.class繼承:
? ES6出了class語法糖之后,就可以通過class定義類并實作類的繼承,直接看例子:
//定義一個父類 Animal
class Animal {
//這里constructor指向類本身,跟es5行為一樣的
constructor(name) {
this.name = name;
}
likeEat() {
console.log(this.name + " like eat " + this.food);
}
}
//定義一個子類 Dog ,通過 extends 繼承父類Animal
class Dog extends Animal {
constructor(name, food) {
//通過super(屬性名)繼承父類屬性
super(name);
this.food = food;
}
likeEat() {
//通過super.+父類方法 實作繼承父類方法
super.likeEat();
}
}
new一個Dog實體,測驗看看,Dog是否繼承了Animal:
var jinmao = new Dog("jinmao", "bone");
console.log(jinmao.name);
jinmao.likeEat();
可以看到完美實作了:

七.總結:
| 方法 | 優點 | 缺點 |
|---|---|---|
| 原型鏈繼承 | 能繼承父原型上屬性方法等等… | 無法傳參、參考型別屬性沖突等等… |
| 借用建構式繼承 | 可以傳參,參考型別屬性不沖突等等… | 無法繼承父原型上方法等等… |
| 組合繼承 | 有上面兩種的優點,并解決其缺點 | 呼叫兩次父實體產生兩份相同屬性等等… |
| 寄生組合繼承 | 有上面三種優點,并解決其缺點 | 可能不太直觀等等… |
| class繼承 | es6新語法,簡潔直觀等等… | 低版本ie不支持es6等等… |
上面就是這篇文章的全部內容啦,如果有錯誤的地方懇請指出~
下次見啦,拜拜~
其它文章:
~關注我看更多簡單創意特效:
文字煙霧效果 html+css+js
環繞倒影加載特效 html+css
氣泡浮動背景特效 html+css
簡約時鐘特效 html+css+js
賽博朋克風格按鈕 html+css
仿網易云官網輪播圖 html+css+js
水波加載影片 html+css
導航欄滾動漸變效果 html+css+js
書本翻頁 html+css
3D立體相冊 html+css
霓虹燈繪畫板效果 html+css+js
記一些css屬性總結(一)
Sass總結筆記
…等等
進我主頁看更多~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/297858.html
標籤:其他
上一篇:Java專案:招聘網站專案設計和實作(java+springboot+jsp+mysql+Spring)
下一篇:箭頭函式=>
