繼承的本質是原型鏈
實作繼承的幾種方式
JS繼承方式
一、借助建構式實作繼承
原理:用 apply、call 修改函式運行的背景關系,通過這種呼叫把父級即 Parent1 建構式在子函式就是說子類函式里面執行的話同時修改父級建構式this執行,也就是指向了child1實體化的物件參考,修改this指向,導致父類執行時屬性都會掛在child1 子類上去
缺點:
這種方式的繼承,父類原型物件(prototype)上的方法(屬性)沒有被子類繼承,只實作部分繼承,沒有實作真正繼承,能繼承建構式上的方法,但是不能繼承父類原型物件的方法(屬性)
1 function Parent1 () { 2 this.name = 'parent1' 3 } 4 5 // Parent1.prototype.say = function () { 6 // } 7 8 function Child1 () { 9 Parent1.call(this) //用apply 也可以, 10 11 this.type = 'child1' 12 } 13 14 // console.log(new Child1, new Child1().say())
二、 借助原型鏈實作繼承
原理:每個建構式都有prototype 屬性,子類.prototype 是一個物件,這個物件可以任意賦值,這個時候賦值給父類 Parent2 一個實體,當實體化子類Child2時,有 new Child2().__proto__, new Child2().__proto__ === Child2.prototype,所以有 new Child2().__proto__.name 這個屬性,值是: 'parent2'
缺點:原型鏈中的原型物件是共有的,實體改變其值,其他實體對應的屬性也會改變
1 function Parent2 () { 2 this.name = 'parent2' 3 this.play = [1, 2, 3] 4 } 5 6 function Child2 () { 7 this.type = 'child2' 8 } 9 Child2.prototype = new Parent2() 10 console.log(new Child2) 11 // console.log(new Child2().__proto__ === Child2.prototype) 12 // console.log(new Child2().__proto__.name) 13 14 var s1 = new Child2() 15 var s2 = new Child2() 16 console.log(s1.play, s2.play) 17 s1.play.push(4)
三、 組合方式
原理:結合了建構式和原型鏈實作繼承的組合方式
缺點:父級的建構式執行了兩次,一次是 new 實體化子類的時候,一次是Child3.prototype又執行了一次,沒有必要執行兩次,并把父類的constructor 也繼承了
1 function Parent3 () { 2 this.name = 'Parent3' 3 this.play = [1, 2, 3] 4 } 5 6 function Child3 () { 7 Parent3.call(this) 8 this.type = 'child3' 9 } 10 Child3.prototype = new Parent3() 11 var s3 = new Child3() 12 var s4 = new Child3() 13 s3.play.push(4) 14 console.log(s3.play, s4.play)
四、 組合繼承的優化1
這種方式的優點,父類只執行一次,在實體化子類的時候執行了一次,原型物件上只是簡單的參考,js上的數值有參考型別和值型別,這里都是物件,所以都是參考型別,所以這一塊不會再執行父級的建構式
缺點:把 父類的 constructor 也繼承了,Child4.prototype = Parent4.prototype, prototype里有 constructor,子類的constructor 是從父類的constructor繼承的
1 function Parent4 () { 2 this.name = 'Parent4' 3 this.play = [1, 2, 3] 4 } 5 6 function Child4 () { 7 Parent4.call(this) 8 this.type = 'child4' 9 } 10 Child4.prototype = Parent4.prototype //js上的數值型別有參考型別和值型別,這里都是物件,所以都是參考型別,所以這一塊不會再執行父級的建構式 11 var s5 = new Child4() 12 var s6 = new Child4() 13 // s5.play.push(4) 14 console.log(s5, s6) 15 // console.log(s5.play, s6.play) 16 console.log(s5 instanceof Child4, s5 instanceof Parent4) 17 console.log(s5.constructor)
五、組合繼承的優化2
原理: 通過 Object.create 方法創建一個中間物件,它創建該物件的原型物件就是引數,然后把子類的建構式賦值為該子類
1 function Parent5 () { 2 this.name = 'Parent5' 3 this.play = [1, 2, 3] 4 } 5 6 function Child5 () { 7 Parent5.call(this) 8 this.type = 'child5' 9 } 10 Child5.prototype = Object.create(Parent4.prototype) // __proto__; 通過 Object.create 方法創建一個中間物件,它創建該物件的原型物件就是引數,然后把子類的建構式賦值為該子類 11 Child5.prototype.constructor = Child5 12 var s7 = new Child5() 13 console.log(s7 instanceof Child5, s7 instanceof Parent5) // true, true 14 console.log(s7.constructor)
ES6 class 繼承方式
1、子類繼承父類要用 extends,子類里面要用 supper()
1 // 父類 2 class People { 3 constructor(name) { 4 this.name = name 5 } 6 eat() { 7 console.log(`${this.name} eat something`) 8 } 9 } 10 11 // 子類 12 class Student extends People { 13 constructor(name, number) { 14 super(name) 15 this.number = number 16 } 17 sayHi() { 18 console.log(`姓名 ${this.name} 學號 ${this.number}`) 19 } 20 } 21 22 // 子類 23 class Teacher extends People { 24 constructor(name, major) { 25 super(name) 26 this.major = major 27 } 28 teach() { 29 console.log(`${this.name} 教授 ${this.major}`) 30 } 31 } 32 33 34 const xialuo = new Student('夏洛', 100) 35 console.log(xialuo.name) 36 console.log(xialuo.number) 37 xialuo.sayHi() 38 xialuo.eat() 39 40 console.log(xialuo.hasOwnProperty('name')) // true 41 console.log(xialuo.hasOwnProperty('sayHi')) //false 42 console.log(xialuo.hasOwnProperty('eat')) //false 43 44 // 實體 45 const wanglaoshi = new Teacher('王老師', '語文') 46 console.log(wanglaoshi.name) 47 console.log(wanglaoshi.major) 48 wanglaoshi.teach() 49 wanglaoshi.eat()
2、super關鍵字
super這個關鍵字,既可以當作函式使用,也可以當作物件使用,當作函式使用時,super代表父類的建構式,并在子類中執行Parent.apply(this),從而將父類實體物件的屬性和方法,添加到子類的this上面,以下三點需要特別注意:
1)子類必須在constructor方法中呼叫super方法,如果子類沒有定義constructor方法,constructor方法以及其內部的super方法會被默認添加,
2)在子類的constructor方法中,只有呼叫super之后,才可以使用this關鍵字,否則會報錯,
3)super作為物件時,在子類中指向父類的原型物件,即super=Parent.prototype,
3、static關鍵字
在一個方法前加上關鍵字static,就表示該方法不會被實體繼承,但是父類的靜態方法,會被子類繼承,
1 // 父類 2 class People { 3 constructor(name) { 4 this.name = name 5 } 6 static showName(name) { 7 console.log(name) 8 } 9 eat() { 10 console.log(`${this.name} eat something`) 11 } 12 } 13 14 // 子類 15 class Student extends People { } 16 17 Student.showName('zhangsan') // zhangsan 18 19 var p = new People() 20 p.showName('zhangsan') //Uncaught TypeError: p.showName is not a function
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/224901.html
標籤:其他
下一篇:this系結的優先級
