JavaScript入门教程

JavaScript简介
JavaScript语法基础
JavaScript流程控制
JavaScript函数
面向对象编程
JavaScript事件
JavaScript DOM
正则表达式
JavaScript BOM
AJAX

专题分析

浏览器兼容性
JS优化
Web前端开发规范
编辑器推荐
总结和笔记

学习助手

对象参考手册
ECMAScript分析
数据中心
QQ交流群

工具包 Base

Base 是由 Dean Edwards 开发的一个 JavaScript 的面向对象的基础包,Base 本身很小,只有 140 行,但是这个很小的包对面向对象编程风格有很好的支持,支持类的定义,封装,继承,子类调用父类的方法等,代码的质量也很高,而且很多项目都在使用 Base 作为底层的支持。尽管如此,JavaScript 的面向对象风格依然非常古怪,并不可以完全和传统的 OO 语言对等起来。

下面我们来看几个基于 Base 的例子,假设我们现在在开发一个任务系统,我们需要抽象出一个类来表示任务,对应的,每个任务都可能会有一个监听器,当任务执行之后,需要通知监听器。我们首先定义一个事件监听器的类,然后定义一个任务类:
var EventListener = Base.extend({
    constructor : function(sense){
        this.sense = sense;
    },
    sense : null,
    handle : function(){
        print(this.sense+" occured");
    }
});
var Task = Base.extend({
    constructor : function(name){
        this.name = name;
    },
    name : null,
    listener : null,
    execute : function(){
        print(this.name);
        this.listener.handle();
    },
    setListener : function(listener){
        this.listener = listener;
    }
});

创建类的方式很简单,需要给 Base.extend 方法传入一个 JSON 对象,其中可以有成员和方法。方法访问自身的成员时需要加 this 关键字。而每一个类都会有一个 constructor 的方法,即构造方法。比如事件监听器类(EventListener)的构造器需要传入一个字符串,而任务类(Task)也需要传入任务的名字来进行构造。好了,既然我们已经有了任务类和事件监听器类,我们来实例化它们:
var printing = new Task("printing");
var printEventListener = new EventListener("printing");
printing.setListener(printEventListener);
printing.execute();

首先,创建一个新的 Task,做打印工作,然后新建一个事件监听器,并将它注册在新建的任务上,这样,当打印发生时,会通知监听器,监听器会做出相应的判断:
printing
printing occurred

既然有了基本的框架,我们就来使用这个框架,假设我们要从 HTTP 服务器上下载一个页面,于是我们设计了一个新的任务类型,叫做 HttpRequester:
var HttpRequester = Task.extend({
    constructor : function(name, host, port){
        this.base(name);
        this.host = host;
        this.port = port;
    },
    host : "127.0.0.1",
    port : 9527,
    execute : function(){
        print("["+this.name+"] request send to "+this.host+" of port"+this.port);
        this.listener.handle();
    }
});

HttpRequester 类继承了 Task,并且重载了 Task 类的 execute 方法,setListener 方法的内容与父类一致,因此不需要重载。

var requester = new HttpRequester("requester1", "127.0.0.1", 8752);
var listener = new EventListener("http_request");
requester.setListener(listener);
requester.execute();

我们新建一个 HttpRequester 任务,然后注册上事件监听器,并执行之:
[requester1] request send to 127.0.0.1 of port 8752
http_request occured

应该注意到 HttpRequester 类的构造器中,有这样一个语句:
    this.base(name);
表示执行父类的构造器,即将 name 赋值给父类的成员变量 name,这样在 HttpRequester的实例中,我们就可以通过 this.name 来访问这个成员了。这套机制简直与在其他传统的OO 语言并无二致。同时,HttpRequester 类的 execute 方法覆盖了父类的 execute 方法,用面向对象的术语来讲,叫做重载。

在很多应用中,有些对象不会每次都创建新的实例,而是使用一个固有的实例,比如提供数据源的服务,报表渲染引擎,事件分发器等,每次都实例化一个会有很大的开销,因此人们设计出了单例模式,整个应用的生命周期中,始终只有顶多一个实例存在。Base 同样可以模拟出这样的能力:
var ReportEngine = Base.extend({
    constructor : null,
    run : function(){
        //render the report
    }
});
很简单,只需要将构造函数的值赋为 null 即可。好了,关于 Base 的基本用法我们已经熟悉了,下节我们要做一个实例。