John Resig的Simple JavaScript Inheritance学习

本文深入探讨JavaScript中的继承机制,介绍了一种通过构造函数定义变量并在原型中实现继承的方法。此外,还详细解释了如何利用基类提供的extend方法来创建新的派生类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * 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;
  };
})();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值