对John Resig 的Simple JavaScript Inheritance的详细分析

最近想开发一个web在线的流程设计器,在网上找了很多js绘图框架,后来发现draw2d.js可以满足我的需求。
在使用draw2d的过程中,发现draw2d的Canvas等核心对象都是通过Class.extend()得来的,于是对Class.js(其实就是John Resig的Simple JavaScript Inheritance)进行了详细的分析,demo编写理解。
下面将代码与我的理解(以注释的形式)贴出来,供参考。
//加载后自执行完,向window注册了一个Class函数,这个函数上定义了一个extend函数
(function () {
    // /xyz/.test(function () { xyz; })的结果一定是true,为什么不直接写成var fnTest = /\b_super\b/;
    // 猜测是作者要通过这种写法告诉读者:/\b_super\b/在后面的代码中也是要这么用,去检测函数中是否有_super
    var fnTest = /xyz/.test(function () {
        xyz;
    }) ? /\b_super\b/ : /.*/;//返回RegExp正则对象/\b_super\b/
    this.Class = function () {
    }; //相当于window.Class=function(){};
    //Class是一个函数,也是一个对象,可以在上面定义函数属性extend
    //这个extend不是原型链上的,是直接定义在构造函数上的,有点像java中的静态方法的意思
    Class.extend = function (prop) {
        var _super = this.prototype; //this指向extend方法的调用者(_super是父类构造函数的prototype,比如Person.prototype)
        console.log("1 " + (this == window.Class) + " , " + (this == Person));

        //控制init的执行时机
        initializing = true;
        //创建一个父类对象,作为原型,此时不执行init方法
        var prototype = new this(); //第一层子类(直接通过Class.extend()方式创建的类)执行时相当于new window.Class();
        console.log("2 " + (prototype.__proto__ === _super));//true,对象的原型指向构造函数的prototype属性
        initializing = false;

        //向prototype中copy传入对象的属性
        for (var name in prop) {
            prototype[name] =
                typeof prop[name] == "function" &&  //传入对象的属性是函数
                typeof _super[name] == "function" &&  //父类prototype上有同名函数
                fnTest.test(prop[name])  //传入对象的属性是函数,并且函数名或函数体包含_super,说明这个函数要调用父类的函数
                    ?
                    (function (name, fn) { //闭包的结构,避免始终返回循环的最后一个
                        console.log("name=" + name);//调用extend时执行
                        return function () {  //调用对象的具体方法时执行
                            var tmp = this._super; //this指向正在创建的对象
                            console.log("3 " + (this == s));//false,因为此时的this还没有返回赋值给s
                            console.log("s=" + s);//undefined
                            that = this;
                            console.log("tmp=" + tmp);
                            this._super = _super[name]; //子类对象上绑定父类的同名函数,命名为_super
                            var ret = fn.apply(this, arguments);//调用子类对象的函数,在调用过程中可能会调用父类的同名函数,所以需要在上一步中先进行绑定
                            this._super = tmp; //执行完后还原,一般tmp为undefined
                            return ret;
                        };
                    })(name, prop[name]) : //函数包含_super的情况,特殊处理为了让子类函数中能调用父类的同名函数
                    prop[name]; //其它的情况,直接copy
        }

        //傀儡构造函数,实际名称是var指定的,比如Person
        function Class() {
            //调用extend函数创建类时不会调用init,真正new子类对象时才会执行init
            if (!initializing && this.init)
                this.init.apply(this, arguments);
        }

        //指定原型对象
        Class.prototype = prototype;
        //指定原型对象的构造器
        Class.prototype.constructor = Class;
        //把extend函数沿着继承层次传递下去,比如Person.extend, Student.extend
        Class.extend = arguments.callee;
        return Class;
    };
})();

附上一个测试的代码demo

var Person = Class.extend({
    init: function () {
        console.log("Person init");
    },
    eat: function () {
        console.log("Person eat");
    },
    data1: "data1"
});
console.log("=============================");
var Student = Person.extend({
    init: function () {
        console.log("Student init");
        this._super();
    },
    eat: function () {
        this._super();
    },
    study: function () {
        console.log("Student study");
    },
    data2: "data2"
});
console.log("=============================");
var that;
var s = new Student();
console.log(that == s);//true

demo的输出结果如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值