- commonjs导入语法本质总结
require的本质:
- 根据导入的路径得到一个唯一的id(完成的绝对路径)
- 判断是否有缓存
- 运行模块代码,实际上是把导入的模块放入一个辅助函数里面(可通过直接打印arguments验证)。函数传入5个参数,伪代码如下:
_require(exports, require, module, __fileName, __dirName){
...
}
- 运行辅助函数
// _require里的module参数
var module = {
exports: {}
}
// _require里的exports参数
var exports = module.exports;
// 使用了call绑定了this, this指向了exports
__require.call(exports, .....);
// 所以到这里其实 module.exports === exports === this
// __fileName和__dirName得到文件的路径,并把运行结果缓存,缓存的是module.exports
cache[moduleId] = module.exports;
// 最后实际返回的就是module.exports
return module.exports;
分析此commonjs导出结果
this.a = 0;
export.b = 1;
exports = {
c: 2
}
module.exports = {
d: 3
}
exports.e = 5;
this.f = 6;
//
// 结果
{
d: 3
}
分析上图
this
exports
module.exports
// 12步骤三者运行都是
{
a:0,
b:1,
}
// 3步骤,exports整体赋值覆盖,此时exports!==this,!==module.exports
// exports更新为
{
c: 2
}
// 4步骤module.exports被整体赋值覆盖,此时!==this
module.exports = {
d: 3
}
// 5步骤exports更新为
{
c: 2,
e: 5
}
// 6步骤this更新
{
a:0,
b:1,
f:6
}
至此结束
this = {
a:0,
b:1,
f:6
}
exports = {
c: 2,
e: 5
}
module.exports = {
d: 3
}
最终返回的是module.exports,所以require的时候导入的就是
{
d: 3
}
-
总结require
- 动态导入。可以在条件语句中require
- 同步加载,require是同步的,模块在执行require时会立即加载并返回结果
- 导出的是值的浅拷贝,对于引用类型,修改引用类型的属性会在所有引用中反映出来。
-
总结es6
- 采用import和export来导入导出
- 静态引入,import必须在文件顶部声明,不能再函数体或者条件语句中使用,使得es6模块可以在编译时确定依赖关系和优化(树摇tree shaking的实现)
- 异步加载,不会阻塞页面其他加载过程
- 导出的是值的引用
-
总结区别
- 语法方面,commonjs使用require和module.exports, es6使用import和export
- 加载方式:commonjs同步加载,es6静态分析异步加载
- 使用场景:commonjs主要用于node环境,es6是ECMAScript标准