[TOC]
AMD (Asynchronous Module Definition ):AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行。
define(id?, dependencies?, factory);
if module "a/b/c" asks for "../d", that resolves to "a/d"
if module "a/b/c" asks for "./e", that resolves to "a/b/e"
defined("alpha", ["require", "exports", "beta"],function(require, exports, beta){
return beta.verb();
})
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出的 // 文件目录
- www/
- index.html
- js/
- app/
- sub.js
- lib/
- jquery.js
- canvas.js
- app.js
- require.js
- app/
使用方式:
//index.html 中导入script标签,data-main 单文件入口app.js src是requirejs包文件
<script data-main="js/app.js" src="js/require.js"></script>
//app.js:
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app',
jquery:'jquery'
}
});
// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],function($, canvas,sub) {
//jQuery, canvas and the app/sub module are all
//loaded and can be used here now.
});
//sub.js
defined([jquery],function($){
return{
body:$('#id')
}
})
//或者
define(function () {
//Do setup work here
return {
color: "black",
size: "unisize"
}
});
CMD (Common Module Definition):CMD推崇就近依赖,只有在用到某个模块的时候再去移入
CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的
define(function(require, exports, module) {
// 通过 require 引入依赖
var $ = require('jquery');
var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
});
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出的
值得注意的是:AMD和CMD都是异步加载模块。
// index.html
<script src="seajs"></scrpt>
<script>
// seajs 的简单配置 可以忽略
seajs.config({
base: "../sea-modules/",
alias: {
"jquery": "jquery/jquery/1.10.1/jquery.js"
}
})
// 加载入口模块文件
seajs.use("../static/hello/src/main.js")
</script>
// main.js
// 所有模块都通过 define 来定义
define(function(require, exports, module) {
// 通过 require 引入依赖
var $ = require('jquery');
var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
});
commonjs Node 应用由模块组成,采用 CommonJS 模块规范。
特点: 所有代码都运行在模块作用域,不会污染全局作用域。 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。 模块加载的顺序,按照其在代码中出现的顺序。
// 导出
var addX = function (value) {
return value + x;
};
// module.exports.addX = addX;
module.exports = addX;
exports.addX = addX;
//导入
var example = require('./example.js');
module.exports 赋值之前 exports == module.exports 赋值之后 exports != module.exports
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作
commonjs 和 commonjs2 区别以及影响 exports是module.exports的引用,module.exports是exports的具体实现 打印 module
Module {
id: '.',
exports: {},
parent: null,
filename: '/home/jim/Desktop/index.js',
loaded: false,
children: [],
paths:
[ '/home/jim/Desktop/node_modules',
'/home/jim/node_modules',
'/home/node_modules',
'/node_modules' ] }
commonjs规定了exports才是正统,module.exports最多只能算'小妾'。所以commonjs2是规定用module.exports输出的。
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
es6 模块静态方式导入
// a.js
export let count = 1;
export default let key = 'degal'
// b.js
import keys {count} from './b.js'
// keys == key , count == count
每个模块只有一个 export default 通过标签引入es6模块需要加module
<script type="module">
import {f2} from "./index2.js"
f2(1);
</script>
es6 与 commonjs区别
| es6模块是引用 | commonjs模块是拷贝 |
|---|---|
| 静态化,必须在顶部,不能使用条件语句,自动采用严格模式, | 当使用require命令加载某个模块时,就会运行整个模块的代码,并缓存下来。 |
| import只会导入一次,无论你引入多少次 | require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。 |
| import的变量是只读的,不论是基本数据类型还是复杂数据类型。 | require导入缓存中,基本类型可以直接赋值,但是对缓存中没影响,引用类型属于浅拷贝,数据改变会影响另一个模块。 |
| 可以通过一些方法调用改变内部值,import加载的值也会发生变化 | 可以通过一些方法调用改变内部值,import加载的值不会发生变化 |
| 外部可以拿到实时值,而非缓存值(是引用而不是copy) | 外部拿到的是缓存值(是copy而不是引用) |
| treeshaking和编译优化,以及webpack3中的作用域提升 | 当使用require命令加载某个模块时,就会运行整个模块的代码。 |
| 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。 | 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。 |
| export default 不能重复导出,会报错 | module.exports 可以重复定义,后面的会覆盖前面的 |
自己理解循环引用: 对于commonjs对于已经全部加载完成的模块,无须加载直接,对于未加载的模块,首次需要正常加载,记载一部分然后内部加载其他模块的部分,再次引用无需加载直接读取加载部分缓存,(如缓存部分没有导出,接下来使用的是undefined,有导出正常导出),未加载的部分无缓存也无需加载。 对于es6模块,无须关注加载,正常执行,(可能导致栈溢出)
amd 扩展
对于一些文件不遵循amd规范可以通过shim方式加载
require.config({
baseUrl:'js/utily',//指定js文件的基路径
paths: {
framework: "framework"
},
shim:{
'framework':{//这个键名为要载入的目标文件的文件名,不能随便命名否则加载framework.js文件后是拿不到改文件对外提供的接口的。因为这个坑了哥一下午!!!
exports:'framework'//exports的值为framework.js提供的 对外接口的名称
}
}
});
require(['framework'],function(frame){
console.log(frame);//此处就会打印framework.js中对外提供的接口对象啦哈啊哈
}