一、CommonJS:服务端模块化规范
1、加载机制:输入的是被输出值的拷贝。一旦输出,模块内部变化就影响不到这个值。
2、所有代码都运行在模块作用域。
3、模块可以多次加载,但只在第一次加载时运行一次,其结果会被缓存。后面再加载的时候,就直接读取缓存结果。要想让模块再运行的话,,必须清除缓存。(delete require.cache[moduleName])
4、模块加载的顺序,按照其在代码中出现的顺序。
5、module对象:
- module.id:模块的标识符,通常是带有绝对路径的模块文件名。
- module.filename: 模块的文件名,带有绝对路径。
- module.loaded:模块是否已经加载完成。
- module.parents:[],调用该模块的模块。node下执行,会得到null或者undefined,require引入的会返回它的调用模块。可以用此判断该模块是不是入口模块。
- module.exports:表示模块对外输出的值。还有个exports变量,指向的是module.exports。不能直接将 exports 变量指向一个值,因为这样等于切断了 exports 与 module.exports 的联系。
6、require:用于加载模块文件。
- 步骤:读入并执行一个js文件,返回该模块的exports对象。若没有发现指定模块则报错。
- 加载规则:加载文件的后缀默认是.js。 | require参数 | 加载规则 | | —- | —- | | ‘/‘开头 | 加载的是绝对路径的文件 | | ‘./‘开头 | 加载的是相对路径的文件 | | 不以/或者./开头 | 默认提供的核心模块(位于Node的系统安装目录中)或者一个位于各级node_modules目录的已安装模块 | | 不以/或./开头,是一个路径 | 先找第一级的位置,再依次往后续找 |
指定的模块没发现的话,node会尝试为文件名添加.js,.json,.node后缀来找。
三、UMD(Universal Module Definition)希望提供一个前后端跨平台的解决方案
- 以此判断是否支持Nodejs模块格式:(typeof exports === ‘object’),是否支持AMD(typeof define === ‘function’),都不支持则将模块公开到全局(window或global)。
四、ES6 Module:浏览器和服务器通用的模块解决方案
1、静态化。编译时就能确定模块的依赖关系;commonjs和AMD只能在运行时确定。
- 不在需要UMD模块格式了。
- 不再需要对象作为命名空间。
- 将来浏览器新的API就能用模块格式提供,不在必须做成全局变量或者navigator对象的属性。
2、es6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。缺点:没法引用es6模块本身,因为它不是对象。
3、自动采用严格模式,所以严格模式的规则,es6模块要遵守。
4、导入和导出:import和export。
- 都可以使用as别名。export语句输出的接口,与其对应的值是动态绑定的。
- 可以出现在模块顶层的任何位置,不能处于块级作用域内,否则会报错。因为这样就没法做静态优化了。
- import命令输入的变量都是只读的。不允许在加载模块的脚本里面改写接口。以下情况要注意: ```javascript import { a } from ‘./xxx.js’ a = {}; // 报错,a是只读的
a.foo = ‘hello’; // 不报错,但是其他模块也可以读到改写后的值,引起bug,所以不能这么操作。
1. import命令有提升效果,会提升到整个的头部。本质:import是静态的,在编译阶段执行,所以import也不能使用表达式或者变量表示。
1. import会执行所加载的模块,不可省略模块后缀名。
```javascript
import './test.js'; // 会直接加载并执行test.js的代码。
export * from ‘circle’; export var e = 2.71828182846; export default function(x) { return Math.exp(x); } ```