一、使用SeaJS开发JavaScript的基本原则就是:一切皆为模块。引入SeaJS后,编写JavaScript代码就变成了编写一个又一个模块,SeaJS中模块的概念有点类似于面向对象中的类——模块可以拥有数据和方法,数据和方法可以定义为公共或私有,公共数据和方法可以供别的模块调用。
每个模块应该都定义在一个单独js文件中,即一个对应一个模块。
二、模块的定义和编写
fn.define = function(id, deps, factory) { //code of function… }
如果只有一个参数,则赋值给factory。
如果有两个参数,第二个赋值给factory;第一个如果是array则赋值给deps,否则赋值给id。
如果有三个参数,则分别赋值给id,deps和factory。
但是,包括SeaJS的官方示例在内几乎所有用到define的地方都只传递一个工厂函数进去,类似与如下代码:
define(function(require, exports, module) { //code of the module... });
id是一个模块的标识字符串,define只有一个参数时,id会被默认赋值为此js文件的绝对路径。
没有特别的必要建议不要传入id。deps一般也不需要传入,需要用到的模块用require加载即可。
三、工厂函数
三个参数:
- require——模块加载函数,用于记载依赖模块。
- exports——接口点,将数据或方法定义在其上则将其暴露给外部调用。
- module——模块的元数据。
下面说一下module。module是一个对象,存储了模块的元信息,具体如下:
- module.id——模块的ID。
- module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。
- module.exports——与exports指向同一个对象
四、三种编写模块的模式
第一种定义模块的模式是基于exports的模式:
是一种比较“正宗”的模块定义模式。除了将公共数据和方法附加在exports上,也可以直接返回一个对象表示模块
define(function(require, exports, module) { var a = require('a'); //引入a模块 var b = require('b'); //引入b模块 var data1 = 1; //私有数据 var func1 = function() { //私有方法 return a.run(data1); } exports.data2 = 2; //公共数据 exports.func2 = function() { //公共方法 return 'hello'; } });
第二种:和上面的模式功能相同
define(function(require) { var a = require('a'); //引入a模块 var b = require('b'); //引入b模块 var data1 = 1; //私有数据 var func1 = function() { //私有方法 return a.run(data1); } return { data2: 2, func2: function() { return 'hello'; } }; });
第三种:如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:对于定义纯JSON数据的模块非常合适。
define({ data: 1, func: function() { return 'hello'; } });
五、模块的载入和引用
上文说过一个模块对应一个js文件,而载入模块时一般都是提供一个字符串参数告诉载入函数需要的模块,所以就需要有一套从字符串标识到实际模块所在文件路径的解析算法。
根据应用场景的不同,SeaJS提供了三个载入模块的API,分别是seajs.use,require和require.async
1.seajs.use
seajs.use主要用于载入入口模块。
//单一模式 seajs.use('./a'); //回调模式 seajs.use('./a', function(a) { a.run(); }); //多模块模式 seajs.use(['./a', './b'], function(a, b) { a.run(); b.run(); });
SeaJS会顺着入口模块解析所有依赖模块并将它们加载。如果入口模块只有一个,也可以通过给引入sea.js的script标签加入”data-main”属性来省略seajs.use
<script src="./sea.js" data-main="./init"></script>
2.require
require是SeaJS主要的模块加载方法,当在一个模块中需要用到其它模块时一般用require加载:
SeaJS的自动加载机制。上文说过,使用SeaJS后html只要包含sea.js即可,那么其它js文件是如何加载进来的呢?SeaJS会首先下载入口模块,然后顺着入口模块使用正则表达式匹配代码中所有的require,再根据require中的文件路径标识下载相应的js文件,对下载来的js文件再迭代进行类似操作。整个过程类似图的遍历操作(因为可能存在交叉循环依赖所以整个依赖数据结构是一个图而不是树)。
传给require的路径标识必须是字符串字面量,不能是表达式,如下面使用require的方法是错误的:
3.require.async
SeaJS会在html页面打开时通过静态分析一次性记载所有需要的js文件,如果想要某个js文件在用到时才下载,可以使用require.async:
require.async('/path/to/module/file', function(m) { //code of callback... });
六、seajs全局配置
SeaJS提供了一个seajs.config方法可以设置全局配置,接收一个表示全局配置的配置对象。具体使用方法如下:
seajs.config({ base: 'path/to/jslib/', alias: { 'app': 'path/to/app/' }, charset: 'utf-8', timeout: 20000, debug: false });
其中base表示基址寻址时的基址路径
alias可以对较长的常用路径设置缩写。
charset表示下载js时script标签的charset属性。
timeout表示下载文件的最大时长,以毫秒为单位。
debug表示是否工作在调试模式下。