第一步javascript
只要把不一样的函数(以及记录状态的变量)简单地放在一块儿,就算是一个模块。Global全局污染,容易命名冲突html
function foo(){ //... } function bar(){ //... }
第二步 Namespacejava
虽然减小了Global变量的数量,可是这样的写法会暴露全部模块成员,内部状态能够被外部改写。jquery
var name = { foo: function(){ }, bar: function(){ } } // 使用 name.foo();
第三步 IIFE模式webpack
闭包模式,经过当即执行函数写法,能够达到不暴露私有变量的目的。且外部没法访问内部的值。es6
var module = (function(){ var _private = 'sss'; var foo = function(){ } return { foo: foo } })(); module.foo(); module._private; // undefined
引入依赖web
// 改进一些 var Module = (function($){ var _$body = $("body"); // we can use jQuery now! var foo = function(){ console.log(_$body); // 特权方法 } // Revelation Pattern return { foo: foo } })(jQuery) Module.foo();
// 依赖其余 var module1 = (function (mod){ mod.m3 = function () { //... }; return mod; })(module1);
// 其余扩展 var MODULE = (function (my) { // add capabilities... return my; }(MODULE || {})); // 能够传入空对象
var MODULE = (function (my) { var old_moduleMethod = my.moduleMethod; my.moduleMethod = function () { // 方法重载 // 可经过 old_moduleMethod 调用之前的方法... }; return my; }(MODULE)); // 有时咱们要求在扩展时调用之前已被定义的方法,这也有可能被用于覆盖已有的方法。这时,对模块的定义顺序是有要求的。
Script Loader
经过script标签引入一堆的依赖,按序执行。一样难以维护,依赖过多。编程
body script(src="zepto.js") script(src="jhash.js") script(src="fastClick.js") script(src="iScroll.js") script(src="underscore.js") script(src="handlebar.js") script(src="datacenter.js") script(src="deferred.js") script(src="util/wxbridge.js") script(src="util/login.js") script(src="util/base.js") script(src="util/city.js") script(src="util/date.js") script(src="util/cookie.js") script(src="app.js")
这样的写法有很大的缺点。首先,加载的时候,浏览器会中止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,因为js文件之间存在依赖关系,所以必须严格保证加载顺序(好比上例的1.js要在2.js的前面),依赖性最大的模块必定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
CommonJS 征服世界的第一步是跳出浏览器。segmentfault
CommonJS规范的提出,主要时为了弥补js没有标准的缺陷,使得经过CommonJS Api编写的应用能够在不一样的宿主环境中执行。浏览器
由于老实说,在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;可是在服务器端,必定要有模块,与操做系统和其余应用程序互动,不然根本无法编程。所以Node就在Commonjs的基础上应运而生了。
【NodeJS
是CommonJS
规范的实现,webpack
也是以CommonJS
的形式来书写】
AMD/CMD 浏览器环境模块化方案
AMD(Asynchronous Module Definition:异步模块定义)
是 RequireJS
在推广过程当中对模块定义的规范化产出。
CMD(Common Module Definition:公共模块定义)
是 SeaJS
在推广过程当中对模块定义的规范化产出。
有了服务器端模块之后,很天然地,你们就想要客户端模块。并且最好二者可以兼容,一个模块不用修改,在服务器和浏览器均可以运行。
可是,因为一个重大的局限,使得CommonJS规范不适用于浏览器环境。下面的代码,若是在浏览器中运行,会有一个很大的问题,你能看出来吗?
var math = require('math'); math.add(2, 3);
第二行math.add(2, 3),在第一行require('math')以后运行,所以必须等math.js加载完成。也就是说,若是加载时间很长,整个应用就会停在那里等。
这对服务器端不是一个问题,由于全部的模块都存放在本地硬盘,能够同步加载完成,等待时间就是硬盘的读取时间。可是,对于浏览器,这倒是一个大问题,由于模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。
所以,在浏览器就须要"异步加载"(asynchronous)。这就是AMD
规范诞生的背景。
目前,主要有两个Javascript库实现了AMD规范:require.js
和curl.js
。
Require.JS
Require.JS 的基本功能"模块化加载"。
实例1
// math1.js /* 语法结构: 1. define({函数方法}) */ // 一个没有依赖性的模块能够直接定义对象 define({ name: '测试', add: function(num1, num2) { return num1+num2; } })
// test1.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> require(['math1'], function(math) { console.log(math.name); console.log(math.add(1,3)); }) </script> </body> </html>
实例二
// math2.js /* 语法结构: 2. define([引入其余模块地址],回调函数(引入模块别名)); 别名能够在函数里面去调用其余模块提供的方法 */ // 一个返回对象的匿名模块 define(['math1'], function(math) { var sub = function(num1,num2) { return num1 - num2; } return { add: math.add, sub: sub } })
// test2.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> require(['math2'], function(math) { console.log(math.sub(4,2)); }) </script> </body> </html>
实例三
// math3.js // 定义一个命名模块 define('mymath', ['math2'], function(math) { var multiplication = function(num1, num2) { return num1 * num2; } return { add: math.add, sub: math.sub, mult: multiplication } })
// test3.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> //须要配置一下引入的模块的地址 require.config({ paths:{ 'mymath': 'math3' } }); require(['mymath'], function(math){ console.log(math.mult(3,5)); }) </script> </body> </html>
下图有一些注意事项,可是截图不是本实例的截图
实例四
// math4.js // 一个使用了简单CommonJS转换的模块定义 define(function(require,exports,module){ // 引入其余模块 var math = require('js/1_math'); console.log(math); // 导出(暴露方法:2种方式) // 第一种 // exports.a = math.add; // 第二种 module.exports = { a : math.add } });
// test4.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> </body> <script type="text/javascript" src="js/require.js"></script> <script type="text/javascript"> require(['js/4_math'],function(mytool){ console.log(mytool.a(11,22));//33 }); </script> </html>
一个小demo
// index.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1>My Sample Project</h1> <script src="./script/require.js" data-main="./script/main" charset="utf-8"></script> </body> </html>
// main.js require.config({ baseUrl: 'script', paths: { math: './lib/math1', utils: './utils/utils', jquery: './lib/jquery.min' } }); require(['math','utils','jquery'], function(math, utils, $) { $(function(){ console.log(math.add(1,2)); console.log(utils.utils.sub(4,2)); alert('在加载完math、utils、jquery以后,我执行了'); }) })
//math.js define({ add:function(num1, num2) { return num1+num2; } });
// utils.js define(function(require, exports, module) { var utils = { sub:function(num1, num2) { return num1-num2; } }; module.exports = { utils: utils } })
SeaJS 是一个适用于 Web 浏览器端的模块加载器。这里就先不写了~
你们能够参考文档学习
面向将来的ES6模块标准
2015年6月,ECMAScript2015也就是ES6发布了,JavaScript终于在语言标准的层面上,实现了模块功能,使得在编译时就能肯定模块的依赖关系,以及其输入和输出的变量,不像 CommonJS、AMD之类的须要在运行时才能肯定(例如FIS这样的工具只能预处理依赖关系,本质上仍是运行时解析),成为浏览器和服务器通用的模块解决方案。
更多关于ES6 Modules的资料,能够看一下ES6阮一峰
感谢您的支持!!