在某些库中,经常会看到函数最前面有一个分号。其实是为了防止自动化工具拼接js时,如果前面的js文件的结尾处忘了加分号,拼接出来的代码容易挂,加分号这种行为属于防御式编程。
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。当然,模块开发需要遵循一定的规范,否则各用各的就会乱套了。
var myModule = (function(){ var var1 = 1; var var2 = 2; function fn1(){ } function fn2(){ } return { fn1: fn1, fn2: fn2 }; })();
下面介绍3种常用的JS模块规范:CommonJS,AMD,CMD。
服务器端一般采用同步加载文件,一旦需要某个模块,服务器端便停下来,等待它加载好再执行。而浏览器端要保证效率,需要采用异步加载,预处理,提前将需要的模块文件并行加载好。
CommonJS是服务端规范,AMD和CMD是浏览器端规范。
一、CommonJS
定义时,不用define关键字。
CommonJS有三个全局变量module、exports和require。
// hello.js var hello = "Hello"; module.exports = hello;
// world.js var amodule = require("./hello"); var Result = amodule + "world!"; module.exports = Result;
commonjs,有代表性的是Node.js。
一般不用额外引入什么库,使用node时,就可以像上面这样写。
如果想要对外提供接口的话,可以将接口绑定到module.exports上。
function MyModule() { // ... } if(typeof module !== 'undefined' && typeof exports === 'object') { module.exports = MyModule; }
二、AMD
Asynchronous Module Definition,异步模块定义。
1、定义模块
A、有名,有依赖,有回调函数 define(id,dependencies,factory);
//比如 define('myModule', ['jquery'], function($) {//依赖必须一开始写好 // $ is the export of the jquery module. $('body').text('hello world'); });
B、匿名模块,有依赖,多依赖 define(['dep1','dep2'],function(dep1,dep2){ });
//比如 define(['jquery', './math.js'], function($, math) { // $ and math are the exports of the jquery module. $('body').text('hello world'); });
C、匿名模块,有依赖,单依赖 define(['dep1'],function(dep1){ });
//比如 define(['jquery'], function($) { $('body').text('hello world'); });
D、匿名模块,没有依赖,只定义简单的模块 define(function(){ });
2、加载模块
AMD也采用require()语句加载模块,但是不同于CommonJS,AMD要求两个参数:require([module], callback); 所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
define('myModule', ['jquery'], function($) {//依赖必须一开始写好 // $ is the export of the jquery module. $('body').text('hello world'); }); // using require(['myModule'], function(myModule) {});
AMD,最具代表性的就是RequireJS。
一般要通过script标签引入require.js,再用上述写法。
如果想要对外提供接口,可以这么做:
function MyModule() { // ... } if(typeof define === 'function' && define.amd) { define(function() { return MyModule; }); }
三、CMD
Common Module Definition,通用模块定义,一个模块就是一个文件。
define(function(require, exports, module) { var a = require('./a'); a.doSomething(); var b = require('./b'); // 依赖可以就近书写 b.doSomething(); });
CMD,有代表性的是SeaJS。
一般要通过script标签引入sea.js,再用上述写法。
如果想要对外提供接口,可以这么做:
function MyModule() { // ... } if(typeof define === 'function' && define.cmd) { define(function() { return MyModule; }); }
或者这么做
function MyModule() { // ... } if(typeof define === 'function' && define.cmd) { define(function(require, exports, module) { module.exports = MyModule; } }
四、AMD和CMD
AMD是提前执行依赖的模块(预加载),CMD是延迟执行依赖的模块(懒加载);
AMD推崇依赖前置,CMD推崇依赖就近;
AMD的一个API可以多用,CMD的API职责单一,没有全局require。
AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行。