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){
		// 當前的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、鏈太深之後,會造成子類過度臃腫


個人覺得,較爲簡單的項目,是完全沒必要使用的。

只有項目中,有強烈的上下級繼承關係的時候,纔是它發光發熱的時候。



發佈了33 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章