JavaScript 组件之旅(二):编码实现和算法

作者:太伯 来源:alipay UED 时间:2009-10-09 14:24:00 

目录:

  1. 分析和设计组件

  2. 编码实现和算法

  3. 用 Ant 构建组件

  4. 测试 JavaScript 组件

话说上期我们讨论了队列管理组件的设计,并且给它取了个响亮而独特的名字:Smart Queue. 这次,我们要将之前的设计成果付诸实践,用代码来实现它。

首先,我们要考虑一下它的源文件布局,也就是决定代码如何拆分到独立的文件中去。为什么要这么做呢?还记得上期结尾处我提到这个组件会使用“外部代码”吗?为了区分代码的用途,决定将代码至少分成两部分:外部代码文件和 Smart Queue 文件。
区分用途只是其一,其二,分散到独立文件有利于代码的维护。试想,以后的某一天你决定要在现有的队列管理基本功能之上,添加一些新的扩展功能,或是把它包装成某个实现特定任务的组件,而又希望保持现有功能(内部实现)和调用方式(对外接口)不变,那么将新的代码写到单独的文件是最好的选择。

嗯,下期会重点谈谈文件布局的话题,现在要开始切入正题了。第一步,当然是要为组件创建自己的命名空间,组件所有的代码都将限制在这个顶层命名空间内:


var SmartQueue = window.SmartQueue || {};
SmartQueue.version = '0.1';

初始化的时候,如果碰到命名空间冲突就把它拉过来用。通常这个冲突是由重复引用组件代码导致的,因此“拉过来用”会将对象以同样的实现重写一次;最坏的情况下,如果碰巧页面上另一个对象也叫 SmartQueue, 那不好意思了,我会覆盖你的实现——如果没有进一步的命名冲突,基本上两个组件可以相安无事地运行。同时顺便给它一个版本号。

接着,按三个优先级为 SmartQueue 创建三个队列:


var Q = SmartQueue.Queue = [[], [], []];

每个都是空数组,因为还没有任务加进去嘛。又顺便给它建个“快捷方式”,后面要访问数组直接写 Q[n] 就可以啦。

接下来,我们的主角 Task 隆重登场——怎么 new 一个 Task, 定义在这里:


    var T = SmartQueue.Task = function(fn, level, name, dependencies) {
        if(typeof fn !== FUNCTION) {
            throw new Error('Invalid argument type: fn.');
        }
        this.fn = fn;
        this.level =  _validateLevel(level) ? level : LEVEL_NORMAL;

        // detect type of name
        this.name = typeof name === STRING && name ? name : 't' + _id++;

        // dependencies could be retrieved as an 'Object', so use instanceof instead.
        this.dependencies = dependencies instanceof Array ? dependencies : [];
    };

里面的具体细节就不说了,有必要的注释,一般我们的代码也能做到自我描述,后面代码也是这样。这里告诉客户(使用者):你想新建一个 SmartQueue.Task 实例,就要至少传一个参数给这个构造函数(后 3 个都可以省略进行缺省处理),否则抛出异常伺候。

但是这还不够,有时候,客户希望从已有 Task 克隆一个新实例,或是从一个“残废体”(具有部分 Task 属性的对象)修复出“健康体”(真正的 Task 对象实例),通过上面的构造方式就有点不爽了——客户得这样写:


var task1 = new SmartQueue.Task(obj.fn, 1, '', obj.dependencies);

我很懒,我只想传 fn 和 dependencies 两个属性,不想做额外的事情。好吧,我们来重构一下构造函数:


    var _setupTask = function(fn, level, name, dependencies) {
        if(typeof fn !== FUNCTION) {
            throw new Error('Invalid argument type: fn.');
        }
        this.fn = fn;
        this.level =  _validateLevel(level) ? level : LEVEL_NORMAL;

        // detect type of name
        this.name = typeof name === STRING && name ? name : 't' + _id++;

        // dependencies could be retrieved as an 'Object', so use instanceof instead.
        this.dependencies = dependencies instanceof Array ? dependencies : [];
    };

    var T = SmartQueue.Task = function(task) {
        if(arguments.length > 1) {
            _setupTask.apply(this, arguments);
        } else {
            _setupTask.call(this, task.fn, task.level, task.name, task.dependencies);
        }

        // init context/scope and data for the task.
        this.context = task.context || window;
        this.data = task.data || {};
    };

如此一来,原来的构造方式可以继续工作,而上面的懒人可以这样传入一个“残废体”:


var task1 = new SmartQueue.Task({fn: obj.fn, dependencies: obj.dependencies});

当构造函数收到多个参数时,按之前的方案等同处理;否则,视唯一的参数为 Task 对象或“残废体”。这里通过 JavaScript 中的 apply/call 方法将新实例传给重构出来的 _setupTask 方法,作为该方法的上下文 (context, 也有称为 scope), apply/call 是 JavaScript 在方法之间传递上下文的法宝,要用心体会哦。同时,允许用户定义 task.fn 在执行时的上下文,并将自定义的数据传递给执行中的 fn.

标签:组件,JavaScript,编码,算法
0
投稿

猜你喜欢

  • 浅谈javascript面向对象编程

    2009-03-03 12:04:00
  • GC与JS内存泄露

    2010-09-25 19:01:00
  • 通过FSO进行页面计数

    2008-11-27 16:02:00
  • [JS效果]动画效果打开/关闭/移动层

    2008-04-10 11:42:00
  • 在系统崩溃的时候如何恢复原有的数据

    2009-01-08 13:26:00
  • 小议javascript设计模式

    2009-10-09 13:31:00
  • 三谈Iframe自适应高度

    2010-08-03 13:04:00
  • firefox扩展插件制作方法

    2007-10-12 13:50:00
  • asp正则表达式详细说明

    2008-10-23 16:23:00
  • 深入了解SQL Server 2008 商业智能平台

    2009-01-15 13:03:00
  • WEB页面工具之语言XML的定义

    2008-05-29 11:29:00
  • 快速解决SQL server 2005孤立用户问题

    2009-01-04 14:02:00
  • 关于ASP中脚本执行顺序的讲解

    2008-11-04 12:02:00
  • IIS6.0下ASP的新增功能

    2007-08-22 14:55:00
  • 用XMLHTTP很好的一个例子

    2008-04-25 10:25:00
  • 如何显示数据库里的图片?

    2010-06-08 09:36:00
  • 连接无法用于执行此操作。在此上下文中它可能已被关闭或无效

    2011-03-15 23:03:00
  • 基于ASPJPEG 制作了一个梦寐已久的批量水印工具步骤

    2011-02-28 10:39:00
  • set rs=server.CreateObject("adodb.recordset") 的中文详细说明

    2011-03-06 11:21:00
  • CSS自适应宽度圆角按钮

    2007-11-20 11:38:00
  • asp之家 网络编程 m.aspxhome.com