John Resig的Simple JavaScript Inheritance学习

来源:互联网 发布:哈希map c语言 编辑:程序博客网 时间:2024/06/05 08:44
/** * 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(){  //测试下正则表达式,得到一个_super的正则表达式对象,以检查是否使用了基类的方法  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;  };})();
0 0
原创粉丝点击