網上的衆多javascript繼承方式,這裏是不會詳細講解的,需要的,請自己度娘或谷爹。
之前做cocos2d-js的遊戲,發現它有一個很有趣的繼承方式。
形式如下:
var A = cc.Class.extend({
// 一系列的函數等
ctor: function(){
// this._super指向了父親的ctor方法,不明覺厲啊
this._super();
}
});
於是研究了一下,主要有幾點需要注意的:
1、function.toString會返回整個函數的定義字符串
2、str.indexOf方法,有兩個參數,第一個是字符串,第二個是起始檢查的位置,它第一次匹配上,就結束了
3、它的this._super方法,是通過匹配 或
閉包改寫,弄出來的
於是,嘗試了一下,自己去實現:
function Class(){};
// compileSuper在某些特定情況下,纔有用咯~,不過,它更節省內存空間,如果不需要調試,可以啓用這種繼承
Class.compileSuper = function(fnStr, fnName){
// 找出fn的參數
var pstart = fnStr.indexOf("("), pend = fnStr.indexOf(")");
var params = fnStr.slice(pstart + 1, pend);
// 從fn主體開始尋找
var str = fnStr.substring(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}"));
// 替換掉this._super,爲this.super[name]
// cocos2d-js裏,是通過for循環來實現的,但因爲這裏多記錄了一個super字段,所以沒有它的煩惱~
var keyName = "this.super." + fnName;
str = str.replace(/this._super/g, "this.super && " + keyName + " && " + keyName);
// 返回新的函數
return new Function(params, str);
};
Class.extend = function(proto){
var _super = this.prototype;
function myClass(){
this.ctor && this.ctor.apply(this, arguments);
};
var fn = myClass.prototype;
// 下面這個for循環,如果再包裝一下,就可以實現多參數形式了~,實驗,不過多考慮
for(var key in proto){
// 當前的item
var item = proto[key];
// 如果父類和當前,都是函數,則有繼承關係
var isSuperFunc = "function" == typeof _super[key], isFunc = "function" == typeof item;
if(isFunc && isSuperFunc){
// 實現繼承,包裝一個super方法,如果存在_super這樣的字段,則編譯
var reg = /\b_super\b/, itemStr = item.toString();
if(reg.test(itemStr)){
// 有_super方法,則編譯super方法
// 但是一點都不好調試,可以考慮在其它模式下【如不想被別人調試的時候...】,使用這種編譯
// 這裏主要做實驗,就不一一操作了
// fn[key] = Class.compileSuper(itemStr, key);
// 放棄編譯的方法,使用閉包
fn[key] = (function(key, proto){
return function(){
var tmp = this._super;
// 這一句依賴後面的 fn.super = _super;
this._super = this.super[key];
var res = item.apply(this, arguments);
this._super = tmp;
return res;
};
})(key, item);
}else{
fn[key] = item;
}
}else{
fn[key] = item;
}
};
// 可以通過super尋找到父類
fn.super = _super;
myClass.extend = fn.extend = Class.extend;
return myClass;
};
因無法調試等原因,丟棄了匹配【重新編譯字符串】的實現,使用了閉包。
但是閉包帶來了額外的內存消耗,所以,如果真正上線,最好還是使用匹配的實現。
下面看兩個例子:
var myFirst = Class.extend({
constroctor: myFirst,
ctor: function(name){
// 因爲父類Class,沒有ctor方法,所以this._super(name);的調用,會報錯
// this._super(name);
console.log(name);
}
});
var mySecond = myFirst.extend({
ctor: function(name, age){
// 繼承了myFirst,因爲myFirst有ctor方法,所以,this._super(name)正常使用
this._super(name);
console.log(age);
}
});
// 最終數據:
var ss = new mySecond("da宗熊", 26);
// 輸出: da宗熊 26
代碼看着挺優雅的,
但這種實現,也有一定的侷限性:1、約定了ctor爲構造函數,new操作,實際調用了ctor的操作【可容忍】
2、繼承沒有篩選屬性,會把父類的所有屬性繼承下來
3、鏈太深之後,會造成子類過度臃腫
個人覺得,較爲簡單的項目,是完全沒必要使用的。
只有項目中,有強烈的上下級繼承關係的時候,纔是它發光發熱的時候。