終於要說到JavaScript的繼承瞭,原型鏈繼承是最常用的一種方式:
Java代碼
function Video(){};
function Movie(){};
Movie.prototype = new Video();
Movie.prototype.constructor = Movie; //不要丟失構造器
囉嗦一句,如果我拿到的是方法的實例,一樣可以做繼承:
Java代碼
function Video(){};
function Movie(){};
var video = new Video();
video.size = 3;
video.toString = function(){
return "video";
};
video.getName = function(){
return "VideoXXX";
};
var movie = new Movie();
(function inherit(parent,child){
for(var ele in parent){
if(!child[ele]) //在child不包含該屬性或者方法的時候,才會拷貝parent的一份
child[ele] = parent[ele];
}
})(video,movie); //匿名函數調用的方式
alert(movie.size); //3
alert(movie.toString()); //[object Object]
alert(movie.getName()); //VideoXXX
可是這種方法是不純粹繼承的,可見其中的toString方法由於是原生方法,無法用var ele in parent遍歷到的。
如果僅僅想覆寫父類的某個方法,還可以使用call或者apply嘗試一下方法的this大挪移,略。
原型鏈繼承看起來似乎是最自然和最具親和力的繼承方式瞭,但是還記得上一節中對於單例模式的處理嗎?我使用瞭getInstance方法去取得一個唯一的實例,而不是new,這樣原型對其實例化起不到作用瞭:
Java代碼
var Player = (function(){
Player = function(){ //這隻是個空殼
throw new Error("Can not instantiate a Player object.");
};
Player.MIN_EXTENDED_TIME = 1;
Player.MAX_EXTENDED_TIME = 3;
Player._player = false;
Player.getInstance = function(){
if(!Player._player){
alert("Init…");
Player._player = {
_name : name,
setName : function(name){
this._name = name;
},
toString : function(name){
return "Player: " + this._name;
}
};
}
return Player._player;
};
return Player; //把修繕完工的Player這個組件方法返回
})();
現在,我要創建一個WindowsMediaPlayer,去繼承上面的Player,怎麼做?
這裡提供兩條思路:
(1)獲取Player的實例,然後遍歷實例中的方法和屬性,構造一個全新的WindowsMediaPlayer,其它的屬性照抄Player,但是唯有getInstance方法需要覆寫。這個方式不夠優雅,而且getInstance方法可能會很復雜和冗餘,也許不是一個很好的思路。
(2)從對象設計的角度來說,一個單例的類,本身就不適合被繼承,那麼,還不如把Player做成一個純粹的抽象層,讓單例這個工作交給其子類WindowMediaPlayer去完成。這個方式要好得多,至於如何把一個function做成一個抽象層,呵呵,咱們下回再說。
作者“四火的BLOG”