一、为什么模块化

    1. 防止全局变量污染

// 全局变量弥足珍贵,不能用的太豪爽啊
// 申明一个 定时器变量
var timer = xxx;

.... 若干行代码之后 或者另外一个文件里

var timer = bbb;

// 传统解决方案 :闭包 ...

(function(){
    var timer = xxx;
})()

  2. 繁琐的依赖关系

项目中,页面依赖的模块不尽相同。有的需要模块 1、2、3,有的依赖模块 2、4、6。 于是你把它们拆到独立的文件里头去,并只在需要它的页面上引用。于是你的页脚成了这个样子:

<!doctype html><html><head></head><body>    <script>var Precious = {};</script>    <script src="mod1.js"></script>    <script src="mod2.js"></script>    <script src="mod3.js"></script></body></html>

    

这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。


主要解决的问题


(1)实现js文件的异步加载,避免网页失去响应;

(2)管理模块之间的依赖性,便于代码的编写和维护。


二、模块定义规范

1.sea.js

A module is defined with define keyword, which is a function.

define(factory);
  1. The define function accepts a single argument, the module factory.

  2. The factory may be a function or other valid values.

  3. If factory is a function, the first three parameters of the function, if specified, must be "require", "exports", and "module", in that order.

  4. If factory is not a function, then the module's exports are set to that object.

// 1.参数是个函数 函数没有参数// 文件名:moddefine(function(){    return function(str){        document.title = str;    }});// 使用var mod = require('mod');mod('xxxxx');----------------------// 2.参数是个函数 函数有参数  模块对外提供 exports 对象// 文件名:moddefine(function(require,exports,module){    module.exports = function(str){        document.title = str;    }})// 使用var mod = require('mod');mod('xxxxx');--------------------------// 3.参数是个函数 函数有参数  模块对外提供 exports 方法// 文件名:moddefine(function(require,exports,module){    exports.setT = function(str){	document.title = str;    }})// 使用var mod = require('mod');mod.setT('xxxxx');--------------------------// 4.参数是个对象// 文件名:moddefine({'maat':'chenxianliang'});// 使用var mod = require('mod');console.log(mod.maat);//chenxianliang--------------------------// 5.参数是个字符串// 文件名:moddefine('ouer');// 使用var mod = require('mod');console.log(mod);//ouer// 一个模块的完整形式  ,也是打包后的模块样子define('mod',[],function(require,exports,module){    module.exports = function(str){        document.title = str;    }})


2.require.js

The specification defines a single function "define" that is available as a free variable or a global variable. The signature of the function:

    define(id?, dependencies?, factory);

模块声明基本同sea.js相同


三、模块调用

    sea.js

var mod = require('./mod');

ID命名
完整绝对路径 例如 "http://example.com/test/js/jquery/jquery.js"
以 "." 开头 例如 "./home/main" "../main"
以 "/" 开头 例如 "/js/home/"
普通命名 例如 "home/main"


ID命名
完整绝对路径 例如 "http://example.com/test/js/jquery/jquery.js"
以 "." 开头 例如 "./home/main" "../main"
以 "/" 开头 例如 "/js/home/"
普通命名 例如 "home/main"


模块路径解析
替换alias
添加base前缀
可以在seajs.config()方法中设置ID别名和基础路径, 例如:

seajs.config({
    base:"js",
    alias: {
        jquery: "/jquery/jquery"
    }
})


举个栗子

例如:

http://example.com/test/js/sea/sea.js

http://example.com/test/index.html

在index.html中调用了sea.js

base的默认值为 "http://example.com/test/js/sea/"

如果使用seajs.config()设置了base

seajs.config({
    base: "home"  // base值为 "http://example.com/test/js/sea/home"
});

seajs.confg({
    base: "./home"  // base值为 "http://example.com/test/home"
});

seajs.conifg({
    base: "/home"   // base值为 "http://example.com/home"
});




2. requirejs

requirejs.config({
    baseUrl: 'js'
});
// 依赖lib.js,实际加载的路径是 js/common/lib.js,而lib模块又依赖于util模块('./util'),解析后的实际路径为 js/common/util.js

require(['common/lib'], function(Lib){
    Lib.say('hello');
});

// 依赖util模块
define(['./util'], function(Util){
    return {
        say: function(msg){
            Util.say(msg);
        }
    };
});

总体和seajs一样


四、入口文件

1.sea.js

  页面载入    seajs.use('main');    //main.js    define(function(){      var $ = require('jquery');  })


2.require.js

页面载入

<script src="js/require.js" data-main="js/main"></script>

// main.js

require('jquery',function($){
    ...
})

//或者

define(function(require){
    var mod1 = require('mod1');
    ...
})



五、sea.js 与 require.js 的不同


玉伯的说法       


执行如下代码

define(function(require, exports, module) {
    console.log('require module: main');

    var mod1 = require('./mod1');
    mod1.hello();
    var mod2 = require('./mod2');
    mod2.hello();

    return {
        hello: function() {
            console.log('hello main');
        }
    };});


sea.js的结果

require module: main
require module: mod1
hello mod1
require module: mod2
hello mod2
helo main


require.js

require module: mod2
require module: mod1
require module: main
hello mod1hello mod2
helo main


可以看出 sea.js 对模块对解析是执行的时候再解析,而require.js是require的时候直接解析。


未完待续...




参考资料 

sea.js官网

require.js官网

requirejs中文网


cmd规范

amd规范


seajs教程系列

seajs 所谓何

高富帅seajs使用示例及spm合并压缩工具露脸

seajs路径解析


require教程系列

require路径解析

阮一峰:Javascript模块化编程(三):require.js的用法


seajs requirejs异同

LABjs、RequireJS、SeaJS 哪个最好用?为什么?


阿拉蕾(基于seajs spm2 的模块库)

基于seajs spm3的模块库