模块化commonjs,amd,cmd,es6简单总结

159 阅读4分钟
  1. 在没有CommonJS和ES6的时候,我们想要达到模块化的效果可能有这么三种: (1) 函数模块:污染了全局变量,无法保证不会与其它模块发生冲突 (2) 对象模块:会暴露所有模块成员,内部的状态可能被改写 (3) 立即函数模块:外部代码就不能读取到内部成员

  2. CommonJS规范 特点:

    • 所有代码都运行在模块作用域,不会污染全局作用域;
    • 模块是同步加载的,即只有加载完成,才能执行后面的操作;
    • 模块在首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存;
    • CommonJS输出是值的拷贝(即,require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值)。 *modules.export输出,require引入。 缺点: CommonJS同步加载的特点不太适合用在客户端(浏览器)环境了;
    • 服务器端所有的模块都存放在本地硬盘中,可以同步加载完成,等待时间就是硬盘的读取时间。
    • 浏览器,所有的模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。 所以AMD出来了。
  3. AMD 特点:

    • 异步的方式加载模块; *define(id?, dependencies?, factory)定义: id: 一个字符串,表示模块的名称; dependencies: 一个数组,是我们当前定义的模块要依赖于哪些模块; factory: 一个函数,具体的模块内容了 return出需要导出的值 *引用时主要有两个Javascript库实现了AMD规范:require.js和curl.js 缺点: 所有依赖dependencies都需要使用AMD规范
  4. CMD 特点: *define(id?, dependencies?, factory),factory参数: require:引入某个模块 exports:当前模块的exports module:当前这个模块 module.exports出需要导出的值

    • AMD中会把当前模块的依赖模块放到dependencies中加载,并在factory回调中拿到加载成功的依赖
    • CMD一般不在dependencies中加载,而是写在factory中,使用require加载某个依赖模块 AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同,二者皆为异步加载模块。 *引用时主要Javascript库实现了CMD规范:seajs AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块; CMD推崇就近依赖,只有在用到某个模块的时候再去require
  5. ES6 Modules 特点:

    • 输出使用export
    • 输入使用import
    • 可以使用export...from...这种写法来达到一个"中转"的效果
    • 输入的模块变量是不可重新赋值的,它只是个可读引用,不过却可以改写属性
    • export命令和import命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,这是因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷。
    • import命令具有提升效果,会提升到整个模块的头部,首先执行。

CommonJS与ES6 Modules规范的区别:

* CommonJS模块是运行时加载,ES6 Modules是编译时输出接口
* CommonJS输出是值的拷贝;ES6 Modules输出的是值的引用,被输出模块的内部的改变会影响引用的改变
* CommonJs导入的模块路径可以是一个表达式,因为它使用的是require()方法;而ES6 Modules只能是字符串
* CommonJS this指向当前模块,ES6 Modules this指向undefined
* 且ES6 Modules中没有这些顶层变量:arguments、require、module、exports、__filename、__dirname
关于第一个差异,是因为CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。