《悟透JavaScript》之 甘露模型(4)

作者:李战 来源:软件真谛 时间:2008-06-09 14:03:00 

这可真是闭包中嵌套着闭包,貌似递归却又不是递归,是高阶函数却又高不可测。一旦整个对象创建完成,用过的内存状态都释放得干干净净,只得到一尘不染的新建对象。JavaScript玩到这样的境界,方显观音大士的法力!

    下面就是是重写后的完美甘露模型代码:

http://www.leadzen.cn/Books/WuTouJavaScript/1/JS25.htm


<script type="text/javascript">
    //定义类的语法甘露:Class()
    //最后一个参数是JSON表示的类定义
    //如果参数数量大于1个,则第一个参数是基类
    //第一个和最后一个之间参数,将来可表示类实现的接口
    //返回值是类,类是一个构造函数
    function Class()
    {
        var aDefine = arguments[arguments.length-1]; //最后一个参数是类定义
        if(!aDefine) return;
        var aBase = arguments.length>1 ? arguments[0] : object; //解析基类
        
        function prototype_(){}; //构造prototype的临时函数,用于挂接原型链
        prototype_.prototype = aBase.prototype;  //准备传递prototype
        var aPrototype = new prototype_();    //建立类要用的prototype
        
        for(var member in aDefine)  //复制类定义到当前类的prototype
            if(member!="Create")    //构造函数不用复制
                aPrototype[member] = aDefine[member];
                
        //根据是否继承特殊属性和性能情况,可分别注释掉下列的语句
        if(aDefine.toString != Object.prototype.toString)
            aPrototype.toString = aDefine.toString;
        if(aDefine.toLocaleString != Object.prototype.toLocaleString)
            aPrototype.toLocaleString = aDefine.toLocaleString;
        if(aDefine.valueOf != Object.prototype.valueOf)
            aPrototype.valueOf = aDefine.valueOf;
if(aDefine.Create)  //若有构造函数
            var aType = aDefine.Create  //类型即为该构造函数
        else    //否则为默认构造函数
            aType = function()
            {
                this.base.apply(this, arguments);   //调用基类构造函数
            };
aType.prototype = aPrototype;   //设置类(构造函数)的prototype
        aType.Base = aBase;             //设置类型关系,便于追溯继承关系
        aType.prototype.Type = aType;   //为本类对象扩展一个Type属性
        return aType;   //返回构造函数作为类
    };
//根类object定义:
    function object(){}    //定义小写的object根类,用于实现最基础的方法等
    object.prototype.isA = function(aType)   //判断对象是否属于某类型
    {
        var self = this.Type;
        while(self)
        {
            if(self == aType) return true;
            self = self.Base;
        };
        return false;
    };
    
    object.prototype.base = function()  //调用基类构造函数
    {
        var Base = this.Type.Base;  //获取当前对象的基类  
        if(!Base.Base)  //若基类已没有基类
            Base.apply(this, arguments)     //则直接调用基类构造函数
        else    //若基类还有基类         
        {
            this.base = MakeBase(Base);     //先覆写this.base
            Base.apply(this, arguments);    //再调用基类构造函数
            delete this.base;               //删除覆写的base属性
        };
        function MakeBase(Type) //包装基类构造函数
        {
            var Base = Type.Base;
            if(!Base.Base) return Base; //基类已无基类,就无需包装
            return function()   //包装为引用临时变量Base的闭包函数
            {
                this.base = MakeBase(Base);     //先覆写this.base
                Base.apply(this, arguments);    //再调用基类构造函数
            };
        };
    };
//语法甘露的应用效果:    
    var Person = Class      //默认派生自object基本类
    ({
        Create: function(name, age)
        {
            this.base();    //调用上层构造函数
            this.name = name;
            this.age = age;
        },
        SayHello: function()
        {
            alert("Hello, I'm " + this.name + ", " + this.age + " years old.");
        },
        toString: function()    //覆写toString方法
        {
            return this.name;
        }
    });
    
    var Employee = Class(Person,    //派生自Person类
    {
        Create: function(name, age, salary)
        {
            this.base(name, age);  //调用基类的构造函数
            this.salary = salary;
        },
        ShowMeTheMoney: function()
        {
            alert(this + " $" + this.salary); //这里直接引用this将隐式调用toString()
        }
    });
var BillGates = new Person("Bill Gates", 53);
    var SteveJobs = new Employee("Steve Jobs", 53, 1234);
    alert(BillGates);   //这里将隐式调用覆写后的toString()方法
    BillGates.SayHello();
    SteveJobs.SayHello();
    SteveJobs.ShowMeTheMoney();
    
    var LittleBill = new BillGates.Type("Little Bill", 6); //用BillGate的类型建LittleBill
    LittleBill.SayHello();
    
    alert(BillGates.isA(Person));       //true
    alert(BillGates.isA(Employee));     //false
    alert(SteveJobs.isA(Person));       //true
</script>

当今的JavaScript世界里,各式各样的AJAX类库不断出现。同时,在开放Web API的大潮中,AJAX类库作为Web API最重要的形式,起着举足轻重的作用。这些AJAX类库是否方便引用,是否易于扩展,是否书写优雅,都成了衡量Web API质量的重要指标。

甘露模型基于JavaScript原型机制,用及其简单的Class()函数,构造了一个非常优雅的面向对象的类机制。事实上,我们完全可以在这个甘露模型的基础上打造相关的的AJAX类库,为开发人员提供简洁而优雅的Web API接口。

想必微软那些设计AJAX架构的工程师看到这个甘露模型时,肯定后悔没有早点把AJAX部门从美国搬到咱中国的观音庙来,错过了观音菩萨的点化。

当然,我们也只能是在代码的示例中,把Bill Gates当作对象玩玩,真要让他放弃上帝转而皈依我佛肯定是不容易的,机缘未到啊!如果哪天你在微软新出的AJAX类库中看到这种甘露模型,那才是真正的缘分!

广告时间:《悟透JavaScript》一书,共分三部分,
       第一部分 JavaScript真经 (博客原文扩编)
       第二部分 手谈JavaScript (讲述JavaScript操纵DOM)
       第三部分 点化AJAX (AJAX思维升华)

就算你不看,也可以给孩子当故事书。如果你还没孩子,就当给自己买本幽默的漫画书。

原创 * :李战(leadzen)

幕后指使:电子工业出版社-博文视点公司

标签:类,class,javascript,模型
0
投稿

猜你喜欢

  • 也谈网页圆角的背景图法

    2009-03-19 14:09:00
  • 用Dreamweaver设计自动关闭的网页

    2010-09-02 12:29:00
  • 将各种类型或对象都转变为数组

    2009-12-28 13:19:00
  • 10个提高网站可用性的实用技巧[译]

    2009-06-12 12:37:00
  • 15个网页排版例子赏析

    2008-01-06 16:38:00
  • JavaScript for: i++ vs i–

    2010-06-24 21:42:00
  • HTML和CSS中的视觉语义

    2010-07-09 13:08:00
  • asp如何计算下载一个文件需要多长时间?

    2009-11-25 20:17:00
  • 网易网站设计(思想)

    2009-03-27 17:51:00
  • 使用 XMLSPY 设计项目的 Schema 原型

    2010-08-24 18:25:00
  • CODEPAGE=936是什么意思?

    2009-07-05 18:37:00
  • 两个百度WEB面试题 怎么做?

    2010-09-03 18:40:00
  • 实例剖析:MySQL数据库优化详解

    2008-11-22 12:19:00
  • 嵌入Flash应该考虑不支持Flash的浏览器

    2007-12-20 12:29:00
  • 排序与检索

    2008-05-18 13:09:00
  • ASP压缩ACCESS数据库实例

    2009-01-19 11:47:00
  • ASP处理多关键词查询实例代码

    2008-11-21 17:36:00
  • 讲解无法打开用户默认数据库的解决方法

    2008-12-05 15:55:00
  • Web设计师的出路问题

    2009-06-08 13:07:00
  • 从语义开始–概念、意义、实践

    2010-06-13 18:06:00
  • asp之家 网络编程 m.aspxhome.com