es6 module和commonJs对比
es6 module
es6 module import
1.无法动态加载,import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
}
es6 module export
// export-default.js
export default function () {
console.log('foo');
}
commonJs
commonJs特点:
所有代码都运行在模块作用域,不会污染全局作用域。
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
模块加载的顺序,按照其在代码中出现的顺序
commonJs导入require
1.require主要识别.js、 .json 或 .node等后缀,.js 文件会被解析为 JavaScript 文本文件, .json 文件会被解析为 JSON 文本文件。 .node 文件会被解析为通过 process.dlopen() 加载的编译后的插件模块,其他的后缀全部按js加载。
2..以 '/' 为前缀的模块是文件的绝对路径。
3.以 './' 为前缀的模块是相对于调用 require() 的文件的
4.require加载node_module时,向上逐级递归,直到根目录下的node_modules目录
新建index.js,内容如下
console.log(module.paths);
执行
node index.js
结果如下
5.每次导入模块,都会module将其封装,好处变量这些是不会污染全局,并且传入快捷变量 __filename 和 __dirname
(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});
6.优先从缓存加载
function wrapper (script) {
return '(function (exports, require, module, __filename, __dirname) {' +
script +
'\n})'
}
function require(id) {
var cachedModule = Module._cache[id];
if(cachedModule){
return cachedModule.exports;
}
const module = { exports: {} }
// 这里先将引用加入缓存 后面循环引用会说到
Module._cache[id] = module
//当然不是eval这么简单
eval(wrapper('module.exports = "123"'))(module.exports, require, module, 'filename', 'dirname')
return module.exports
}
7.支持动态导入
if(true){
require("./a/b");
}
commonJs导出
module.exports和export
//一个一个 导出
module.exports.age = 1
module.exports.foo = function(){}
exports.a = 'hello'
//整体导出
module.exports = { age: 1, a: 'hello', foo:function(){} }
//整体导出不能用`exports` 用exports不能在导入的时候使用
exports = { age: 1, a: 'hello', foo:function(){} }
差异
1.CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
CommonJS
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3
JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
2.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
3.CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段
类型 | 加载方式 | 同步或异步 | 输出 |
---|---|---|---|
CommonJS | 动态导入 | 同步 | 输出值拷贝 |
es6module | 静态导入 | 异步 | 输出值引用,需要的时候去加载模块取值 |