javascript的模块系统错综复杂,比较常见的有AMD(requireJs),CMD(sea.js),CommonJS,UMD, ES6 module等等, 本文主要介绍CommonJS与ES module的相关知识及比较二者。
CommonJS
简介
CommonJS用于后端是node.js的模块系统,模块同步加载, 通过require导入模块,通过exports导出模块,模块的载入是动态的,返回一个对象,对象的属性方法也是在运行时确定的。
语法
导入模块
const foo=require('./foo.js')
console.log(foo.age)//1
导出模块
//foo.js
// Export by export
module.exports.age=1
module.exports.foo=function(){}
exports.a='hello'
//Whole export
module.exports={age:1,a:'hello',foo:function(){}}
//Cannot use 'exports' for overall export. Cannot use' exports' for import
exports={age:1,a:'hello',foo:function(){}}
ES module
简介
ES module服务端和客户端都适用,模块是编译时输出接口,接口只是一种静态定义,在代码静态解析阶段就会生成,也支持动态导入模块,语法上通过import导入模块,通过export导出模块。
语法
导出模块
// 代码来自https://programmer.help/blogs/the-difference-between-commonjs-and-es6-module.html#j1
export * from 'module';
export {name1,name2,....,nameN } from 'module';//Redirect named exports 从module中再导出
export {import1 as name1,import2 as name2,...,nameN } from 'module'; //Redirect rename export // 重命名
export {name1,name2,..,nameN};//Bind named exports with previously declared variable names // 导出之前声明的变量
export let name1='name1';//Declare named exports or var,const,function,function*,class
export default expression;//Default export
export default function(){...}//Or function*,class
export default function name1(){...}//Or function*,class
export { name1 as default,...};//Rename to default export
导入模块
//Named export module.js
let a=1,b=2
export {a,b}
export let c=3
//Named import main.js
import {a,b,c} from 'module';//a:1 b:2 c:3
import {a as newA,b,c as newC } from 'module';//newA:1 b:2 newC:3
// Export module.js by default
export default 1
// Import main.js by default
import defaultExport from 'module';//defaultExport:1
// Mixed export module.js
let a=1
export {a}
const b=2
export {b}
export let c=3
export default [1,2,3]
// module.js
Array.prototype.remove=function(){}
//Side effects only run one module
import 'module';//Execute module without exporting value multiple times call module.js only once
//Dynamic import (asynchronous import) 动态导入
var promise=import('module');
CommonJS与ES module的区别
模块导出
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用(default 除外)
// 代码来自https://es6.ruanyifeng.com/#docs/module-loader#ES6-%E6%A8%A1%E5%9D%97%E4%B8%8E-CommonJS-%E6%A8%A1%E5%9D%97%E7%9A%84%E5%B7%AE%E5%BC%82
// 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
// 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
- CommonJs只能导出一个值, ES6 Module可以导出多个值
// CommonJS
module.exports = {a: 1}
// ES6 Module
export default () => {}
let a =1, b = 2, c =3
export {a, b, c}
模块导入
- CommonJS可以通过条件判断动态引入,ES6的静态语法只能写在文件顶部
let a = 1
if(a){
let b = require('./b') // CommonJS可以这样写
import {b} from './b' // ES6 这样就是错的
}
this指向
CommonJS 指向当前模块,ES6模块指向undefined
// CommonJS
module.exports = {
test: function(){
console.log(this) // 指向module.exports
}
}
// ES6 module
export function test(){
console.log(this) // 指向undefined
}
循环加载
“循环加载”(circular dependency)指的是,a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本。es6.ruanyifeng.com/
可以点击上面的链接,看阮一峰老师的教程,它讲的比较透彻,下面我就直接贴他的示例代码了。
CommonJS
// a.js
exports.done = false;
var b = require('./b.js');
console.log('在 a.js 之中,b.done = %j', b.done);
exports.done = true;
console.log('a.js 执行完毕');
// b.js
exports.done = false;
var a = require('./a.js');
console.log('在 b.js 之中,a.done = %j', a.done);
exports.done = true;
console.log('b.js 执行完毕');
// main.js
var a = require('./a.js');
var b = require('./b.js');
console.log('在 main.js 之中, a.done=%j, b.done=%j', a.done, b.done);
// node main
//在 b.js 之中,a.done = false
//b.js 执行完毕
//在 a.js 之中,b.done = true
//a.js 执行完毕
//在 main.js 之中, a.done=true, b.done=true
ES6 module
// a.mjs
import {bar} from './b';
console.log('a.mjs');
console.log(bar());
function foo() { return 'foo' }
export {foo};
// b.mjs
import {foo} from './a';
console.log('b.mjs');
console.log(foo());
function bar() { return 'bar' }
export {bar};
// node --experimental-modules a.mjs
//b.mjs
//foo
//a.mjs
//bar
本文主要介绍了CommonJS与ES6 module的应用场景和简单的语法介绍,比较了它们之间的不同点,大家可以阅读下面的参考文章,了解更多知识。
参考文章
The difference between CommonJs and es6 module
Learn the basics of the JavaScript module system and build your own library