繼承:繼承可以使得子類具有父類的屬性和方法或者重新定義、追加屬性和方法等。在JavaScript中實現繼承的過程中要注意對引用資料型別的處理和對原型上的屬性和方法的繼承。
一、原型鏈的繼承
核心就是將子類的prototype指向父類的例項
function Parent(name){
this.name = name
this.friends = ['f1','f2']
}
Parent.prototype.say = function(){
console.log(`我朋友有${this.friends}`)
}
function Son(school) {
this.school = school
}
Son.prototype = new Parent()
var s1 = new Son('光明小學')
var s2 = new Son('武當小學')
s1.friends.push('f*')
s1.say()
s2.say()
複製程式碼
此時兩個列印的都是我朋友有f1,f2,f*
這顯然不是我們想要的結構,繼承之後的每個屬性應該是屬於每個子類物件的不應該出現互相干擾才對。
此種方法有點就是簡單容易實現。
缺點:1、共享了父類的屬性,2、new Parent()
多執行了父類的構造器函式,3、建立子類物件的時候沒法給父類傳參(Parent的name無法進行賦值)
二、建構函式的繼承
核心:在子類中利用call方法實現父類繼承
function Parent(name,age){
this.name = name
this.age = age
this.friends = ['f1','f2']
this.hello = function() {
console.log(`我是${this.name}`)
}
this.sayFriends = function() {
console.log(`我的朋友是${this.friends}`)
}
}
Parent.prototype.say = function() {
console.log('say')
}
function Son(name, age, school) {
Parent.call(this, name, age)
}
var p1 = new Son('張三', 12)
var p2 = new Son('李四', 13)
p1.friends.push('f*')
p1.sayFriends() //我的朋友是f1,f2,f*
p2.sayFriends() //我的朋友是f1,f2
p1.hello() //我是張三
p1.say() //p1.say is not a function
複製程式碼
以上的列印可以看出這種方式可以實現子類物件屬性的獨立,但是父類原型上的方法屬性子類是訪問不到的。
那麼以上兩種方式結合在一起正好互補了不足之處。
三、原型加建構函式的繼承
function Son(name, age) {
Person.call(this, ...arguments)
}
Son.prototype = Parent.prototype
複製程式碼
這樣將Son的原型直接指向Parent的原型,Son就可以訪問父類原型上的方法了,但是會出現下面這個問題Son的建構函式變成了Parent這是不對的Son的建構函式應該是Son才對。所以就有了最後的寄生組合繼承。
四、寄生組合繼承
核心:利用Object.create建立一個以父類為原型的物件作為子類的原型
function Son(name, age) {
Person.call(this, ...arguments)
}
Son.prototype = Object.create(Parent.prototype);
Son.prototype.constructor = Son;
複製程式碼
該方法應該是最為完善的方案。
五、利用ES6 extends
class Person {
//呼叫類的構造方法
constructor(name, age) {
this.name = name
this.age = age
}
}
class Son extends Person {
constructor(name, age, school) {
super(name, age)//通過super呼叫父類的構造方法
this.school = school
}
}
複製程式碼
這個方法程式碼的可讀性比較高,程式碼更加的好看。extends的實現原理還請各路大神在評論留言。