当前位置:编程学习 > JAVA >>

JavaScript模块化开发库之SeaJS

JavaScript模块化开发库之SeaJS
SeaJS由国内的牛人lifesinger开发。目前版本是1.1.1,源码不到1500行,压缩后才4k,质量极高。
这篇会讲述SeaJS的一些基本用法,不会面面俱到,但会就个人的理解讲述官方文档没有提到的一些细节。
 
一、SeaJS的全局接口
 
SeaJS向全局公开了两个标识符: seajs 和 define。
 
如果你的项目中已经用了标识符seajs,又不想改。这时SeaJS可以让出全局的seajs。如
var boot = seajs.noConflict();
这时boot就相当于先前的seajs。
 
如果你的项目中连标识符define也用到了,也不想改。SeaJS是很宽容的,它的define也可以让出。如
var boot = seajs.noConflict(true);
较上面仅多传了一个true。这时全局的define也没了。这时需要用boot.define来代替之前的define。
 
用过jQuery的同学应该很熟悉$.noConflict方法,SeaJS的noConflict与之类似。
 
二、SeaJS的模块写法
 
SeaJS默认使用全局的define函数写模块(可把define当成语法关键字),define定义了三个形参id, deps, factory。
 
define(id?, deps?, factory);
 
这个define很容易让你想起AMD的唯一API:define函数。 或者说让人费解,导致搞不懂SeaJS和 RequireJS define的区别。
 
它们都有个全局的define,形参都是三个,且对应的形参名也一样,会误认为SeaJS也是AMD的实现。
 
事实上SeaJS和RequireJS的define前两个参数的确一样。
 
id都为字符串,都遵循 Module Identifiers。deps都是指依赖模块,类型都为数组。区别仅在于第三个参数factory,虽然类型也都是函数,但factory的参数意义却不同。
 
RequireJS中factory的参数有两种情况
a、和deps(数组)元素一一对应。即deps有几个,factory的实参就有几个。
 define(['a', 'b'], function(a, b){
    // todo
});
  
b、固定为require,exports, module(modules/wrappings格式)。
 define(function(require, exports, module){
    // todo
});
  
这种方式是RequireJS后期向 Modules/Wrappings 的妥协,即兼容了它。而SeaJS的define仅支持RequireJS的第二种写法:Modules/Wrappings。
注意:SeaJS遵循的是 Modules/Wrappings 和 Modules/1.1.1。这两个规范中都没有提到define关键字,Modules/Wrapping中要求定义模块使用module.declare而非define。而恰恰只有AMD规范中有define的定义。即虽然SeaJS不是AMD的实现,但它却采用了让人极容易误解的标识符define。
 
 
说了这么多,还没开始写一个模块。下面我们从最简单的开始
1、简单模块
 define({
    addEvent: function(el, type, fn){},
    removeEvent: function(el, type, fn){},
    fireEvent: function(el, type){}
});
  
这样就写了一个事件模块,这和写一个单例没有区别。更多的时候用该方式定义纯数据模块。它类似于
 var E = {
    addEvent: function(el, type, fn){},
    removeEvent: function(el, type, fn){},
    fireEvent: function(el, type){}
};
  
2、简单的包装模块
 define(function() {
    // 一些内部辅助函数
    // ...
    function addEvent() {
        // ..
    }
    function removeEvent() {
        // ..
    }
    function fireEvent() {
        // ..
    }
    return {
        addEvent: addEvent,
        removeEvent: removeEvent,
        fireEvent: fireEvent
    };
});
  
您懂的,在这个匿名函数中可以做很多事情。最后只需公开必要的接口。它类似于
 var E = function() {
    // 一些内部辅助函数
    // ...
    function addEvent() {
        // ..
    }
    function removeEvent() {
        // ..
    }
    function fireEvent() {
        // ..
    }
    return {
        addEvent: addEvent,
        removeEvent: removeEvent,
        fireEvent: fireEvent
    };
}();
  
3、NodeJS风格的包装模块
 
上面两种写法看不到一丝NodeJS风格(Modules/1.1.1),改写下与“方式2”等价的。
 define(function(require, exports) {
    // 一些内部辅助函数
    // ...
    function addEvent() {
        // ..
    }
    function removeEvent() {
        // ..
    }
    function fireEvent() {
        // ..
    }
    // 使用exports导出模块接口,而非返回一个对象
    exports.addEvent = addEvent;
    exports.addEvent = removeEvent;
    exports.addEvent = fireEvent;
});
  
可以看到与“方式2”区别在于:
1:匿名函数有两个参数require、exports。
2:导出接口不是return一个对象而是使用exports。
而exports不正是NodeJS的风格吗? 细心的同学可能发现这个示例中require参数没有用到,这正是下面要讲的。
 
4、有依赖的模块
 
SeaJS中“依赖”都需要使用require函数去获取,虽然SeaJS的define的第二个参数deps也有“依赖”的意思,但它是提供打包工具(SPM)用的。此外,SeaJS的require是作为参数传入匿名函数内的,RequireJS的require则是全局变量。 www.zzzyk.com
 
上面定义的是一个没有依赖的模块,以下是有依赖的模块。
 define(function(require, exports) {
    var cache = require('cache');
     
    // ...
     
    exports.bind = bind;
    exports.unbind = unbind;
    exports.trigger = trigger;
});
  
该事件模块依赖于cache模块,函数有两个形参require和exports。抛开外层的匿名函数及define,它就是标准的NodeJS格式:使用require函数取依赖模块,使用exports导出现有模块接口。
实际上在SeaJS中具有依赖的模块必须按“方式4”写,即必须是包装模块,且匿名函数的第一个参数必须是标识符 “require”。即可以把require当初语法关键字来使用,虽然它不是全局的。
 
下面我们看看匿名函数的参数require和exports的一些有趣现象
a、如果写的不是require,改成req会是什么结果。
 define(function(req, exports) {
    var cache = req('cache');
     
    // ...
     
    exports.bind = bind;
    exports.unbind = unbind;
    exports.trigger = trigger;
});

Firebug网络请求如下
 
会看到依赖的“cache”没有被加载,当然JS肯定会报错了。

b、只把匿名函数的形参改成req,函数内部仍然使用require。
 define(function(req, exports) {
    var cache = require('cache');
     
    // ...
     
    exports.bind = bind;
    exports.unbind = unbind;
    exports.trigge

补充:web前端 , JavaScript ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,