CommonJS、AMD、CMD、ES Module
依赖前置和依赖就近
RequireJS采用依赖前置,举个例子就是炒菜前一次性把所有食材洗好,切好,根据内部逻辑把有些酱料拌好,最后开始炒菜,前面任何一个步骤出现问题都能较早发现错误;SeaJS的依赖就近就是要炒青椒了去切青椒要炒肉了去切肉
cmd:例如seajs
amd:例如requirejs
commonjs模块规范 node采用的就是该规范
导入 -,导出:require module.export
es6模块规范 esModule es6原生支持的规范(目前需要使用babel来兼容)
导入 - import,导出 - export
umd 统一模块,支持多种规范混合使用
解决了什么问题呢?
解决变量污染问题,每个文件都是独立的作用域,所以不存在变量污染
解决代码维护问题,一个文件里代码非常清晰
解决文件依赖问题,一个文件里可以清楚的看到依赖了那些其它文件
CommonJs与ES6Module最本质的区别在于前者对模块依赖的解决是动态的,而后者是静态的。
动态:模块依赖关系的建立是发生在代码运行阶段;
静态:模块依赖关系的建立是发生在代码编译阶段;
CommonJS
CommonJS规范 通过model.exports定义的,在前端浏览器中并不支持
NodeJS是CommonJS规范的实现,webpack 也是以CommonJS的形式来书写的。
var foo = require('foo.js');
var count = 1;
var plusCount = () => {
foo.add(count);
};
module.exports = {
count,
plusCount
};
对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值
对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
当使用require命令加载某个模块时,就会运行整个模块的代码。
当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。
CommonJs可以动态加载语句,代码发生在运行时,(也就是可以在代码中加载文件,可以不一定写在文件头部)
Commonjs规范中module.exports和exports的区别
esModule
浏览器端实现模块化的一个很好的方案
a.js
export const name = 'alice'
export const age = 16
b.js
import { name, age } from "./a.js";
console.log(name, age) // alice 16
Es Module是静态的,不可以动态加载语句,只能声明在该文件的最顶部,代码发生在编译时。
export 和 export default,还有 导入的时候,import a from …,import {a} from …,总之也有点乱,那么下面我们就开始把它们捋清楚吧
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
export default命令,为模块指定默认输出
export与export default均可用于导出常量、函数、文件、模块等
在一个文件或模块中,export、import可以有多个,export default仅有一个
通过export方式导出,在导入时要加{ },export default则不需要
export能直接导出变量表达式,export default不行。
1,模块依赖解决方式不同
es6 module与commonjs最本质的区别是两者对模块依赖的解决方式,es6 module是静态的而commonjs是动态的,es6在编译阶段既确定了模块依赖关系及模块导入导出的变量,而commonjs只有在运行阶段才能确定这些。
2,变量导出方式不同
在导入一个模块变量的时候es6 module导出的是变量的动态映射,既在当前模块改变变量会影响导出模块变量,在导出模块改变变量也会影响导入模块变量,因为两者指向的是同一个引用变量,而对commonjs模块变量来说在任一模块改变变量都不影响另一模块,因为引入模块仅仅是对导出模块变量的浅拷贝。