Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145470
  • 博文数量: 54
  • 博客积分: 2682
  • 博客等级: 少校
  • 技术积分: 580
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-24 20:56
文章分类
文章存档

2012年(2)

2011年(10)

2010年(28)

2009年(14)

我的朋友

分类: 系统运维

2010-08-24 09:38:57

记录ext源码阅读第一次尝试~

有人说过,越是对Java用得多的人,越是弄不明白Javascript的OO机制。我果真如此。后来一查,原来这两个OO机制根本就不是同一条道上的,若自以为能按Java那套思维来理解Javascript,你是不可能搞清楚的。Java是class-based OO,而Javascript是prototype-based OO.

我把《javascript高级程序设计》的前7章,抱着一种崇敬神圣的心情仔细阅读了一遍(以前总是抱着一种鄙视Javascript的态度阅读,结果P都没学到)。终于摸清楚了点东西。今天我就可以分析Ext的继承机制的源码了。记录一下这个里程碑似的一天。


extend : function(){
            // inline overrides


            //hdc: 定义一个函数,这个函数是被下面的闭包用到。

            //把o中的属性全部搬到this里来          

            var io = function(o){
                for(var m in o){
                    this[m] = o[m];
                }
            };

 

            //hdc: 记录Object的构造函数,用来判断接下来的sp

            //是不是Object直接子类
            var oc = Object.prototype.constructor;

            //hdc: 我们使用的是这个函数。有两种用法

            // Subclass = Ext.extend(SuperClass, {overrides} )

            // Ext.extend(Subclass, Superclass, {overrides})        

            return function(sb, sp, overrides){

                //hdc:两种用法就通过这个区分。比如以字面量形式

                //表达的对象就在Ext.isObject返回true,而若是

                //Ext.util.Observable,则Ext.isObject返回false
                if(Ext.isObject(sp)){
                    overrides = sp;
                    sp = sb;
                    sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
                }

                //hdc: 之所以加上一个过渡性F

                //是因为以后对subclass所有的原型修改不会直接

                //反应到父类上。这个在《javascript高级程序设计》有讲。

                //也就是说subclass的原型是F,F的原型是SuperClass
                var F = function(){},
                    sbp,
                    spp = sp.prototype;

                F.prototype = spp;
                sbp = sb.prototype = new F();
                sbp.constructor=sb;

                //hdc:有意思的地方。SubClass的实例变量里有个

                //Ext自己加上去的属性:superclass,用来

                //引用父类的原型.见下面。
                sb.superclass=spp;
                if(spp.constructor == oc){
                    spp.constructor=sp;
                }

                // hdc: 到这里继承已经做好了,下面是收尾
                sb.override = function(o){
                    Ext.override(sb, o);
                };

                //hdc:而SubClass原型里面也有一个superclass

                //不过这个superclass是个函数,返回SuperClass

                //的原型。所以你得到SubClass的实例subc后,

                //既可以subc.superclass来访问父类原型,也可以

                //subc.superclass() 或subc.supr()来访问。
                sbp.superclass = sbp.supr = (function(){
                    return spp;
                });
                sbp.override = io;
                Ext.override(sb, overrides);
                sb.extend = function(o){Ext.extend(sb, o);};
                return sb;
            };
        }(),


总结:心中一定要记住javascript原型链图《javascript高级程序设计》书第六章有,这样有助于理解javascript中的诸如:继承,类变量,实例变量,私有变量等等概念。 我记得一个同学说过,牢牢理解并记住半导体的电子扩散图就可以把很多课程学得轻松自如,javascript原型链图就是同样的作用吧。

举个例子:(哎,我也是一知半解):

Ext.ux.Rating = Ext.extend(Ext.util.Observable, {
    // Configuration options

    starWidth: 16, //在Ext.ux.Rating的原型里,相当于静态变量。

    starsLength:10, //在Ext.ux.Rating的原型里

    split: 1, //在Ext.ux.Rating的原型里

    resetValue: '', //在Ext.ux.Rating的原型里

    resetTitle: "重新选择", //在Ext.ux.Rating的原型里

    defaultSelected: -1,     //在Ext.ux.Rating的原型里

    selected: -1,//在Ext.ux.Rating的原型里

    showTitles: true, //在Ext.ux.Rating的原型里

    HideField_name: 'rate',//在Ext.ux.Rating的原型里

    // Our class constructor

    constructor : function(element, config) {
        Ext.apply(this, config);
        Ext.ux.Rating.superclass.constructor.call(this);
        this.addEvents('change', 'reset');
        
        this.el = Ext.get(element);


....

有三个实体。一个是Ext.ux.Rating本身,一个是Ext.ux.Rating的原型,一个是Ext.ux.Rating的实例。主要说一下什么东西放在什么里面。

什么东西在Ext.ux.Rating里面?
上面代码中的constructor的function就是Ext.ux.Rating,所以Ext.ux.Rating就是一个函数,里面的代码就是constructor里的代码。

什么东西在Ext.ux.Rating的原型里面?(在原型里面的都可以类比成java中类的静态变量,是被所有实例共享的)
在Ext.extend(Ext.util.Observable, {})这个{}的东西都放在了Ext.ux.Rating.prototype里面。
所有{}里定义的东西都是“类静态变量”。

什么东西在Ext.ux.Rating的实例里面?
凡属通过this.形式初始化的属性都在实例里面。

三者的关系
var ins = new Ext.ux.Rating(Ext.getBody(), {});
Ext.ux.Rating == Ext.ux.Rating.prototype.constructor  //true
ins.__proto__ == Ext.ux.Rating.prototype //true

分清楚三者的关系个人感觉有利于很多东西的理解,比如Ext.util.Observable,实际上就是一个函数,你要把它当类使唤,那么就是一个构造函数。在Ext文档里定义的那么多methods,实际上都是放在Ext.util.Observable的原型里的。凡属配置的东西,都是放在实例里的。

-------
关于Ext继承中父类构造函数的处理方式

自己琢磨了半天,终于知道为什么下面三个例子的输出会是这样,但是还是没搞懂Ext为什么要这样处理。

        function A(){
            alert('A constructor');
        }
        
        B = Ext.extend(A, {});
        new B();

例子1: 这个输出:  A constructor


        function A(){
            alert('A constructor');
        }
        
        function B() {
            alert('b con');
        }
        
        Ext.extend(B, A, {});
        new B();

例子2:这个输出:  b con



        function A(){
            alert('A constructor');
        }
        
    
        B= Ext.extend(A, {test:'test'});
        
        C = Ext.extend(B, {});
       

        c = new C();

例子3: 这个输出: A constructor

原因就是:
一句话,一个类在new的过程中,一定会调用一个构造函数。若其本身有构造函数(如例子2中的B),那么只会调用本身的构造函数;如果本身没有构造函数(如例子1中的B和例子3中的C),那么Ext.extend中就会为它建立一个构造函数function() {sp.apply(this, arguments)},这个就成为了它的构造函数。其中的sp是父类构造函数。所以在例子1中, new B(),相当于把sp.apply也就是A()调用一遍;而例子3中, new C()相当于把sp.apply也就是B()调用一遍,而B由于本身没有显示的构造函数,其本身也是function() {sp.apply(this, arguments)},所以会把A()调用一遍。

我搞不懂的就是,既然是C继承自B,B继承自A,为什么不像Java那样,在C构造函数调用刚开始的时候,B和A的构造函数都要被默认调用?javascript的继承机制真是晦涩费解啊
阅读(1104) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-08-27 11:15:20

Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com