/** * Created by KBWoniu on 16/6/23. * 歡迎批評指正及任何形式的交流! *//** *Simple JavaScript Inheritance * http://ejohn.org/blog/simple-javascript-inheritance/ *//** * 一.繼承的一般方式 * js中沒有類的標準概念,一等公民為函數,我為了理解和分析方便仍然使用類這個概念 * js繼承的方式一般是在建構函式中加入變數定義,然後重新定義它的原型對象prototype為基類的一個執行個體 * function SuperClass(){} //基類 * SuperClass.prototype.someFunc = function(){ * console.log('SuperClass someFunc'); * }; * * function SubClass() { //衍生類別 * //變數定義 * this.someVal = ''; * } * SubClass.prototype = new SuperClass(); * SubClass.prototype.subFunc = function(){ * console.log('SubClass subFunc'); * }; * * var sub = new SubClass(); * sub.someFunc();//SuperClass someFunc * sub.subFunc(); //SubClass subFunc * * * 二.解析 * 談一下我的理解: * 1.Class理解為基類 * 2.基類Class提供一個extend方法,通過基類調用該方法可以產生一個新的衍生類別 * 3.指定一個對象,這個對象中包含衍生類別的初始化init(如果必要),和其他的一些擴充方法 * 4.關於衍生類別中的override:可以直接覆蓋;可以在衍生類別中調用基類的方法(必須使用this._super()),並且附加內容 * * 來逐條分析下實現思路。為了達到上述的目的: * 1.定義Class函數,作為基類,直接定義在根環境下 * 2.extend方法作為Class的屬性,而不是執行個體屬性,並且返回一個擴充類,因此,必須返回一個類型。看下他的做法,使用了一個dummy類作為返回 * 3.參數對象 * 4.把衍生類別(dummy類)的prototype賦值為基類的執行個體即可。如何複用基類的方法。這是關鍵所在。定義prototype的衍生類別方法。 * 使用this._super指代基類的方法,作為基類的方法來使用,實際調用時將他替換為基類的方法。這樣,參數對象的方法就更新為了 * 基類+新添加的內容的組合了。他採用的方式是,將基類的原型先儲存到_super變數中,更新prototype對應的方法,該方法使用一個 * 匿名函數重新定義。在重新定義的實現中,先把this._super方法進行了替換,替換為基類的方法,之後才真正去調用參數對象的方法。 * 閉包在此起到了舉足輕重的作用:保持基類的原型對象,通過使用匿名函數的立即調用,將參數對象的方法進行了精緻封裝,對於初學js * 的我來說真是歎為觀止。 * 5.prototype有了,派生也就實現了 * * *三.附上代碼注釋 * 原注釋刪掉了,附上的理解,具體使用的例子就不再贅述了 *//* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */(function(){ //測試下Regex,得到一個_super的Regex對象,以檢查是否使用了基類的方法 var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; //基類 this.Class = function(){}; //extend方法 Class.extend = function(prop) { //儲存基類的原型,這個this就是基類類型,就是函數的名稱 var _super = this.prototype; //定義一個基類的執行個體,為了給衍生類別的prototype用,直接跳過了init方法,init方法可以理解為各個類私人的方法,並且不用於派生 initializing = true; var prototype = new this(); initializing = false; //對prototype屬性的重新賦值 for (var name in prop) { prototype[name] = typeof prop[name] == "function" && //必須是函數 typeof _super[name] == "function" && fnTest.test(prop[name]) ? //必須是使用了_super方法 (function(name, fn){ return function() { //儲存原對象 var tmp = this._super; //增加一個_super方法,並且賦值為基類的方法 this._super = _super[name]; //真正調用衍生類別方法,衍生類別方法中的this._super剛剛已經更新為了基類的方法 var ret = fn.apply(this, arguments); //restore this._super = tmp; //傳回值仍然是派生的調用傳回值 return ret; }; })(name, prop[name]) : prop[name];//條件陳述式 } //dummy類 function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } //更新prototype Class.prototype = prototype; //因為上面這句會讓它找不到constructior Class.prototype.constructor = Class; //沒錯,它也是有extend方法的 Class.extend = arguments.callee; //返回了衍生類別 return Class; };})();