模块化是指将一个大的程序文件, 拆分成许多小的文件, 然后将小文件组合起来.
模块化的好处:
CommonJS 的 NodeJS 是针对服务器端的. CommonJS 的 Browserify, AMD, CMD 都是针对浏览器端的.
一个模块只能在另一个模块中被调用. 所有的模块需要汇总到一个主模块中, 然后在页面中加载主模块. (把模块看成c语言里的函数, 把主模块看成main函数, 页面加载主模块即执行main函数)
http://wiki.commonjs.org/wiki/Modules
每个文件都可以当作一个模块
在服务器端: 模块的加载时运行时同步加载的.
在浏览器端: 模块需要提前编译打包处理.
moudule.exports这个对象.exports和module.exports的区别?
module.exports和exports指向同一个内存地址.module.exports指向的内存地址对应的对象.(```module.exports的指向可能发生改变, 使得它和exports指向不同的内存地址).module.exports = {}, 导出多个方法和变量使用exports.xxx = value.
module.exports = valuemodule.exports.xxx = valueexports.xxx = value (上一条的简写)let module2 = require(xxx)xxx为模块名xxx为模块文件路径 <script src="module.js"></script>
modules/module1.js
module.exports = {
msg: 'module1',
foo(){
console.log(this.msg);
}
}
index.js
let module1 = require("./modules/module1");
module1.foo();
modules/module2.js
module.exports = function(){
console.log("module2");
}
index.js
let module2 = require("./modules/module2");
module2();
exports对象
modules/module3.js
exports.foo = function(){ // module.exports.foo 省略 module 的简写
console.log("foo() module3");
}
/**等价于**/
/*
module.exports.foo = function(){
consojle.log("module3);
}
*/
index.js
let module3 = require("./modules/module3");
module3.foo();
modules/module3.js
/* 空 */
index.js
let module4 = require("./modules/module4");
console.log(module4); // {}, module4是一个空对象
Asychromous Module Definition(异步模块定义)
https://github.com/amdjs/amdjs-api/wiki/AMD
专门用于浏览器端, 模块的加载是异步的
AMD规范的作者亲自实现了符合AMD规范的requireJS
requireJS 需要有一个主模块, 并且在主模块中对其它所有相关模块的路径进行配置
定义有依赖的模块时: 显式声明, 依赖注入.
<script data-main='index.js' src='lib/require.js'></script>
主模块不是 define 的而是个立即执行函数
配置paths时不要加.js文件后缀
// 定义没有依赖的模块
define(function(){
let module = {}
return module;
})
define(['module1', 'module2'], function(m1, m2){
let module ={};
return module;
})
(fucntion(){
requirejs.config({
baseUrl: './modules/', // 基本路径
paths: { // 配置路径
module1: './module1', // 不要加js后缀
module2: './module2',
jquery: "../libs/jquery", // jquery可以直接按自定义模块配置
angular: '../libs/angular'
},
shim: { // angular需要单独增加配置
angular: {
exports: 'angular'
}
}
})
requirejs(['module1'], function(module1) {
module1.doSomething();
})
})()
<script data-main="index.js" src="lib/require.js"></script>
目录结构
requirejs
|-js
|-libs
|-require.js
|-modules
|-alerter.js
|-dataSercie.js
|-main.js
|-index.html
```js
// 定义无依赖的模块
define(function () {
let name = "dataService.js";
function getName(){
return name;
}
// 暴露模块
return {getName}
});
```js
define(['dataService'], function(dataService){
let msg = 'alerter.js';
function showMsg(){
console.log(msg, dataService.getName());
}
// 暴露模块
return {showMsg};
});
```js
(function() {
/* 配置模块 */
requriejs.config({
baseUrl: 'js',
paths: {
dataService: '.modules/dataService',
alerter: './modules/alerter'
}
})
/* 使用模块 */
requriejs(['alerter'], function(alerter){
alerter.showMsg();
})
})();
```html
<script data-main='js/main.js' src="js/require.js"> </script>
https://github.com/seajs/seajs/issues/242
专门用于浏览器端, 模块的加载可以是同步, 也可以是异步的
模块使用时才会加载执行
CommonJS与AMD的结合体
阿里巴巴出品
相对另外三个不太重要(官网都出售了…)
Sea.js
http://www.zhangxinxu.com/sp/seajs/
define(function(require, exports, module){
exports.xxx = value;
module.exports = value;
})
define(function(require, exports, module){
/* 引入依赖模块(同步) */
let module2 = require('./module2');
// 使用module2
/* 引入依赖模块(异步) */
require.async('./module3', function(m3){
// 使用module3
});
/* 暴露模块 */
exports.xxx = value;
})
define(function (require){
let m1 = require("./module1");
let m4 = require("./module4");
m1.show();
m2.show();
})
<script type='text/javascript' src='js/libs/sea.js'></script>
<script type='text/javascript'>
seajs.use('./js/modules/main.js'); // 主模块路径
</script>
目录结构
CMD
|-js
|-libs
|-sea.js
|-modules
|-module1.js
|-module2.js
|-module3.js
|-module4.js
|main.js
|-index.html
module1.js, 没有任何依赖关系
define(function(require, exports, module){
let msg = 'module1';
function foo(){
return msg;
}
module.exports = {foo};
})
module2.js, 被module4依赖
define(function(require, exports, module){
let msg = 'module2';
function bar(){
return msg;
}
module.exports = bar;
})
module3.js, 被module4依赖
define(function(require, exports, module){
let msg = 'module3';
function fun(){
return msg;
}
module.exports = {fun};
})
module4.js, 依赖于module2和module3
define(function(require, exports, module){
let msg = 'module4';
// 同步引入
let module2 = require("./module2");
module2();
// 异步引入
require.async("./module3", function(module3){
module3.fun();
})
function fun2(){
console.log("message");
}
exports.fun2 = fun2;
})
```js
define(function(require){
let module1 = require('./module1');
module1.foo();
let module4 = require('./module4');
module4.fun2();
})
```html
<script type='text/javascript' src='js/libs/sea.js'></script>
<script type='text/javascript'>
seajs.use('./js/modules/main.js');
</script>
module1
module2
module4
module3
http://es6.ruanyifeng.com/#docs/module
依赖模块需要编译打包处理
最重要最常用的一个规范
export function foo(){}
export let arr = [];
function foo(){}
let arr = [];
export {foo, arr}
export default () => {
//
}
import * as m1 from "./module1"
m1.doSomething();
import * as m2 from "./module2"
m2.default.doSomething();
import {foo, bar as alias} from './module2'
foo();
import {default as m3} from "./module2"
m3.doSomething();
import m2 from "./module2"
<script type="module" src="./module">
module.doSomething();
</script>
<script type="module">
import module from "./module";
module.doSomething();
</script>
<script type="module">
import module from "./module";
</script>
<script>
module.doSomething(); // 取不到module对象, 必须在module脚本引入后立刻使用
</script>
package.json文件
{
"name": "ex6-babel-browserify",
"version": "1.0.0"
}
npm install babel-cli browserify -gnpm install babel-preset-es2015 --save-dev.babelrc文件. babel干活之前会先读这个配置文件, 读完之后才知道要去干什么. rc是run control的缩写.
{
"presets": ["es2015"]
}
编写遵循es6规范的代码
babel js/src -d js/libbrowserify js/lib/app.js -o js/lib/bundle.js假设有如下代码:
let math = require('math');
math.add(2, 3);
第二行math.add(2, 3),在第一行require(‘math’)之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。
这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。
因此,浏览器端的模块,不能采用”同步加载”(synchronous),只能采用”异步加载”(asynchronous)。这就是AMD规范诞生的背景。