JavaScript繼承方式(1)
前段時間溫故了下JS OO之寫類方式,從這篇開始我們看看JS OO之繼承方式。
面向對象的語言多數都支持繼承,繼承最重要的優點就是代碼復用,從而構建大型軟件系統。如果一個類能夠重用另一個類的屬性和或方法,就稱之為繼承。從這個角度來看看JS的繼承方式。JS中繼承方式與寫類方式息息相關。不同的寫類方式造成不同的繼承方式。各種流行JS庫繼承方式也各不相同。從最簡單的復用開始。
1、構造函數方式寫類,通過方法調用復制父類屬性/字段到子類 實現繼承
這里父類,子類都采用構造函數方式寫,不用原型。子類調用父類函數來復制父類的屬性。
* 父類Polygon:多邊形
* @param {Object} sides
*/
function Polygon(sides) {
this.sides = sides;
this.setSides = function(s) {this.sides=s;}
}
/**
* 子類Triangle:三角形
*/
function Triangle() {
this.tempfun = Polygon;//父類引用賦值給子類的一個屬性tempfun
this.tempfun(3);//調用
delete this.tempfun;//刪除該屬性
this.getArea = function(){};
}
//new個對象
var tri = new Triangle();
console.log(tri.sides);//繼承的屬性
console.log(tri.setSides);//繼承的方法
console.log(tri.getArea);//自有的方法
//缺點是對于Triangle的實例對象用instanceof為父類Polygon時是false
console.log(tri instanceof Triangle);//true
console.log(tri instanceof Polygon);//false
因為 JavaScript中具名函數的多種調用方式 ,子類還可以有以下的多種實現方式。只是在子類中調用父類方法不同而已。
Polygon.call(this,3); //call方式調用父類
this.getArea = function(){};
}
function Triangle() {
Polygon.apply(this,[3]); //apply方式調用父類
this.getArea = function(){};
}
function Triangle() {
var temp = new Polygon(3); //new方式調用父類
for(atr in temp) { //全部復制給子類
this[atr] = temp[atr];
}
this.getArea = function(){};
}
這種方式的缺點是子類的實例對象用instanceof檢查父類時總是false。這與java中繼承"is a "的關系是違背的。
2、原型方式寫類,原型方式繼承
core JS自身的對象系統就是采用原型方式(prototype based)繼承的。或者說core JS沒有采用常見的類繼承(class based)系統,而是使用原型繼承來實現自己的對象系統。工作中我們也可以用原型方式來實現繼承,代碼復用以構建自己的功能模塊。
* 父類Polygon:多邊形
*
*/
function Polygon() {}
Polygon.prototype.sides = 0;
Polygon.prototype.setSides = function(s) {this.sides=s;}
/**
* 子類Triangle:三角形
*/
function Triangle() {}
Triangle.prototype = new Polygon(); //這是原型繼承關鍵的一句
Triangle.prototype.getArea = function(){}
//new個對象
var tri = new Triangle();
console.log(tri.sides);//繼承的屬性
console.log(tri.setSides);//繼承的方法
console.log(tri.getArea);//自有方法
//instanceof測試
console.log(tri instanceof Triangle);//true,表明該對象是三角形
console.log(tri instanceof Polygon);//true,表明三角形也是多邊形
雖然從輸出可以看出子類繼承了父類Polygon的屬性sides和方法setSides,但sides是0,怎么會是三角形呢。還得調用下tri.setSides(3)使之成為三角形。這樣似乎很不方便。不能傳參數,即是原型方式的缺點。優點是正確的維護了"is a"的關系。
3、組合構造函數/原型方式寫類,采用前面種方式繼承
這種方式父類,子類的屬性都掛在構造函數里,方法都掛在原型上。
* 父類Polygon:多邊形
*/
function Polygon(sides) {
this.sides = sides;
}
Polygon.prototype.setSides = function(s) {this.sides=s;}
/**
* Triangle 三角形
* @param {Object} base 底
* @param {Object} height 高
*/
function Triangle(base,height) {
Polygon.call(this,3);//復制父類屬性給自己
this.base = base;
this.height = height;
}
Triangle.prototype = new Polygon();//復制父類方法給自己
Triangle.prototype.getArea = function(){ //最后定義自己的方法
return this.base*this.height/2;
}
//new個對象
var tri = new Triangle(12,4);
console.log(tri.sides);//繼承的屬性
console.log(tri.setSides);//繼承的方法
console.log(tri.base);//自有屬性
console.log(tri.height);//自有屬性
console.log(tri.getArea);//自有方法
//instanceof測試,表明正確的維護了"is a"的關系
console.log(tri instanceof Triangle);//true,表明該對象是三角形
console.log(tri instanceof Polygon);//true,表明三角形也是多邊形