模块化表格对比
模块规范 | 导出命令 | 导入命令 | 静态还是动态 | 值是否被缓存 | 是否采用严格模式 | 加载是否是同步的 | 适应端 | 顶层this指向哪里 |
---|---|---|---|---|---|---|---|---|
es6 module | export | import | 静态 | 值的引用,不会缓存,运行时再根据引用去取值 | 是 | 浏览器和服务端 | undefined | |
commonjs | module.exports | require | 动态,运行时加载 | 会缓存 | 同步 | 服务端 | 指向当前模块 | |
AMD规范 | return或者兼容commonjs的 | 异步 | 浏览器 |
一、es6 module:浏览器和服务器通用的模块解决方案
1、静态化。编译时就能确定模块的依赖关系;commonjs和AMD只能在运行时确定。
优点:
- 不在需要UMD模块格式了。
- 不再需要对象作为命名空间。
- 将来浏览器新的API就能用模块格式提供,不在必须做成全局变量或者navigator对象的属性。
2、es6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。缺点:没法引用es6模块本身,因为它不是对象。
3、自动采用严格模式,所以严格模式的规则,es6模块要遵守。
4、导入和导出:import和export。
- 都可以使用as别名。export语句输出的接口,与其对应的值是动态绑定的。
- 可以出现在模块顶层的任何位置,不能处于块级作用域内,否则会报错。因为这样就没法做静态优化了。
- import命令输入的变量都是只读的。不允许在加载模块的脚本里面改写接口。以下情况要注意:
import { a } from './xxx.js';
a = {}; // 报错,a是只读的
a.foo = 'hello'; // 不报错。但是其他模块也可以读到改写后的值,引起bug,所以不能这么操作。
- import命令有提升效果,会提升到整个的头部。本质:import是静态的,在编译阶段执行,所以import也不能使用表达式或者变量表示。
- import会执行所加载的模块,不可省略模块后缀名。
import './test.js'; // 会直接加载并执行test.js的代码。
- 尽量不要把require和import在一个文件里混用。在一起用的话会先执行import的。
5、es6module可以继承
// circleplus.js
export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
二、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后缀来找。
- require.resolve可以拿到require命令加载的确切文件名。
7、输出的是值的缓存。
三、UMD(Universal Module Definition)希望提供一个前后端跨平台的解决方案。
- 以此判断是否支持Nodejs模块格式:(typeof exports === 'object'),是否支持AMD(typeof define === 'function'),都不支持则将模块公开到全局(window或global)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。