Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 模块化 #7

Open
huangtengfei opened this issue Dec 16, 2015 · 0 comments
Open

JavaScript 模块化 #7

huangtengfei opened this issue Dec 16, 2015 · 0 comments

Comments

@huangtengfei
Copy link
Owner

为何要模块化

将实现某一功能的代码放在函数中,其实就是一个简单的模块:

function module1(){
    ...
}

然而这样会污染全局变量,无法避免与其他模块相同变量的冲突,也无法看出模块成员之间关系。

更进一步,将模块写成一个对象:

var module1 = {
    count: 0,
    m1: function(){
        ...
    }
}

避免了直接用函数封装模块的缺点,但带来的问题是暴露了模块内私有成员。

再进一步,使用 立即执行函数 改进:

var module1 = (function(){
    var count = 0;
    var m1 = function(){
        ...
    };
    return {
        m1: m1
    };
})()

这样就达到了不暴露私有成员的目的。

如果一个模块需要继承(依赖)另一个模块,而且不确定该模块是否定义,可以这样写:

var module1 = (function(module2){
    ...
})(window.module2 || {})

这样就 OK 了,这也正是所谓的 模块化模式

模块的规范

要想模块化就要有模块的规范。Javascript模块规范共有三种:同步加载 CommonJS 、异步加载 AMD 和 通用模块定义 CMD

CommonJS

Node.js 中,使用的是 CommonJS ,比如:

var http = require('http');
var server = http.createServer();

因为对服务器端而言,所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。在浏览器端,显然不能采用这种方式,因为其等待时间取决于网速的快慢,故只能采用 异步方式 AMD

AMD

AMD(Asynchronous Module Definition,异步模块定义)也是采用 require() 语句加载模块:

require([module], callback);

第一个参数 [module],是一个数组,里面的成员就是要加载的模块;第二个参数 callback,则是加载成功之后的回调函数,比如:

require(['underscore'], function(underscore){
    ...
})

CMD

CMD(Common Module Definition,通用模块定义) 是国内发展起来的模块规范。AMD是依赖关系前置,CMD是按需加载。在 CMD 规范中,一个模块就是一个文件。

// CMD
define(function(require, exports, module) {
  var a = require('./a')
  a.doSomething()
  var b = require('./b') // 依赖可以就近书写
  b.doSomething()
})

// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
  a.doSomething()
  b.doSomething()
}) 

模块规范的使用

require.js

使用 require.js的两个目的:

1)实现js文件的异步加载,避免网页失去响应;
2)管理模块之间的依赖性,便于代码的编写和维护。

使用 require.js 的第一步是加载 require.js

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

如果担心加载这个文件,可能造成网页失去响应,可以把它放在网页底部加载,或者加上 defer async="true"defer 是为了支持 IE。

main.js 相当于整个网页的入口代码。

如果主模块的依赖模块和主模块在同一目录,可以在 main.js 直接加载依赖的各模块:

// main.js
require(['moduleA', 'moduleB'], function (moduleA, moduleB){
    ...
});

如果不在同一目录,也可使用 require.config() 方法,对模块的加载行为进行自定义。

require.config({
    baseUrl: "js/lib",
    paths: {
        "jquery": "jquery.min",
        "underscore": "underscore.min"
    }
});

可以这样定义一个 moduleA 模块

// moduleA.js
define(function (){
    ...
});

如果 moduleA 有依赖,可以这样定义

// moduleA.js
define(['moduleB'], function (moduleB){
    ...
});

更多的使用可参考 StartAPI

sea.js

html 页尾,通过 script 引入 sea.js 后,进行简单配置:

// seajs 的简单配置
seajs.config({
  base: "../sea-modules/",
  alias: {
    "jquery": "jquery/jquery/1.10.1/jquery.js"
  }
})

// 加载入口模块
seajs.use("../static/hello/src/main")

模块的定义:

// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var $ = require('jquery');
  var Spinning = require('./spinning');

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

});

Node.js 极其相近的写法。

以上摘自 Sea.js 的 快速上手 示例,更多可参考 API 文档

参考

  1. Javascript模块化编程
  2. 详解JavaScript模块化开发
  3. 再谈 SeaJS 与 RequireJS 的差异
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant