JS 的繼承
基於原型的繼承
function DOG(name){
this.name = name;
}
DOG.prototype = { species : '犬科' };
var dogA = new DOG('大毛');
var dogB = new DOG('二毛');
alert(dogA.species); // 犬科
alert(dogB.species); // 犬科
species屬性放在prototype物件裡,是兩個例項物件共享的。只要修改了prototype物件,就會同時影響到兩個例項物件。
DOG.prototype.species = '貓科'; alert(dogA.species); // 貓科 alert(dogB.species); // 貓科
由於所有的例項物件共享同一個prototype物件,那麼從外界看起來,prototype物件就好像是例項物件的原型,而例項物件則好像"繼承"了prototype物件一樣。
這就是Javascript繼承機制基於原型的繼承。
function Parent(name1){ this.name1 = name1 } Parent.prototype.pMethod = function(){ console.log(this.name1) } function Child(name2, name1){ Parent.call(this, name1) // 得分點 this.name2 = name2 } Child.prototype.__proto__ = Parent.prototype //上面這句程式碼的古板寫法應該是下面三句 //const empty = function(){} //empty.prototype = Parent.prototype //Child.prototype = new empty() Child.prototype.cMethod = function(){ console.log(this.name2) }
基於 class 的繼承
新的關鍵字class從ES6開始正式被引入到JavaScript中。class的目的就是讓定義類更簡單。
我們先回顧用函式實現Student
的方法:
function Student(name) {
this.name = name;
}
Student.prototype.hello = function () {
alert('Hello,' + this.name + '!');
}
如果用新的class
關鍵字來編寫Student
,可以這樣寫:
class Student { constructor(name) { this.name = name; } hello() { alert('Hello, ' + this.name + '!'); } }
比較一下就可以發現,class
的定義包含了建構函式constructor
和定義在原型物件上的函式hello()
(注意沒有function
關鍵字),這樣就避免了Student.prototype.hello = function () {...}
這樣分散的程式碼。
最後,建立一個Student
物件程式碼:
var xiaoming = new Student('小明');
xiaoming.hello()
class繼承
用class
定義物件的另一個巨大的好處是繼承更方便了。想一想我們從Student
派生一個PrimaryStudent
需要編寫的程式碼量。現在,原型繼承的中間物件,原型物件的建構函式等等都不需要考慮了,直接通過extends
來實現:
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name); // 記得用super呼叫父類的構造方法!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
注意PrimaryStudent
的定義也是class關鍵字實現的,而extends
則表示原型鏈物件來自Student
。子類的建構函式可能會與父類不太相同,例如,PrimaryStudent
需要name
和grade
兩個引數,並且需要通過super(name)
來呼叫父類的建構函式,否則父類的name
屬性無法正常初始化。PrimaryStudent
已經自動獲得了父類Student
的hello
方法,我們又在子類中定義了新的myGrade
方法。
ES6引入的class
和原有的JavaScript原型繼承有什麼區別呢?實際上它們沒有任何區別,class
的作用就是讓JavaScript引擎去實現原來需要我們自己編寫的原型鏈程式碼。簡而言之,用class
的好處就是極大地簡化了原型鏈程式碼。
class Parent{
constructor(name1){
this.name1 = name1
}
pMethod(){
console.log(this.name1)
}
}
class Child extends Parent{
constructor(name2, name1){
super(name1) // 得分點
this.name2 = name2
}
cMethod(){
console.log(this.name2)
}
}