JavaScript重構(六):利用繼承來做事

終於要說到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”
 

You May Also Like