javascript繼承學習(一),javascript繼承學習
網上的眾多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){// 當前的itemvar 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、鏈太深之後,會造成子類過度臃腫
個人覺得,較為簡單的項目,是完全沒必要使用的。
只有項目中,有強烈的上下級繼承關係的時候,才是它發光發熱的時候。