CommonJs和EsModule的由来
在早期 JavaScript
的使用过程中,都是通过 script
标签来引入 js
代码。当 js
代码引入过多时,就会发生以下几个问题:
- 变量污染问题,因为每个文件都不存在独立的作用域,使用不同文件定义的变量存在相互污染的问题
- 文件依赖问题,因为文件依赖不明确,无法确定具体依赖哪些文件
- 代码组织不清晰,不易于维护
而 CommonJs
和 EsModules
就是为了解决以上问题而诞生的。
CommonJs
CommonJS
是一组用于在 JavaScript
上实现模块的标准。该项目由 Mozilla
工程师 Kevin Dangoor
于2009年启动。CommonJS
主要应用于 node
应用,浏览器不支持使用 CommonJS
。而之后 webpack
的出现,让模块化也运用到了前端。
EsModules
从 ES6
开始,JavaScript
支持称为 ES Module
或 ECMAScript Modules
的模块格式。这是 JavaScript
支持模块化的现代方法。
目前有以下环境支持:
- Node.js - Node 12 开始
- Deno
- 浏览器 - 包括 Chrome,Firefox 和 Safari 从2018年开始支持 Es Modules
CommonJs基本语法
对 CommonJs
模块规范来说,每个文件就是一个模块,有自己的作用域。在这个文件内定义的变量、函数、类,都是私有的,对其他文件不可见。
导出
CommonJs
中使用 module.exports
导出变量函数等
// 导出任意值 module.exports.num = 11 module.exports.words = 'Hello World!' module.exports.isShow = true // 也可以写成 exports exports.num = 11 exports.words = 'Hello World!' exports.isShow = true
// 导出对象 module.exports = { num:11, words:'Hello World!', isShow:true } // 也可以写成 exports exports = { num:11, words:'Hello World!', isShow:true }
注意:exports 是 node 为了方便,在每个模块提供了一个 exports 变量,指向 module.exports。所以不能直接将 exports 指向单个值。具体可看
CommonJS规范
// 无效 exports = function(x) {console.log(x)};
// 无效 exports.hello = function() { return 'hello'; }; module.exports = 'Hello world';
为了不增加心智负担,还是不推荐使用 exports
,只使用 module.exports
。
导入
CommonJs
中使用 require
语法进行导入,即读入并执行一个 JavaScript
文件,然后返回该模块的 exports
对象。如果没有发现指定模块,则会报错。
// work.js module.exports.num = 11 module.exports.words = 'Hello World!' module.exports.isShow = true // index.js let work = require('./work.js') console.log(work) // { num:11,words:'Hello World!',isShow:true } let num = require('./work.js').num console.log(num) // 11
CommonJs 支持动态导入,即在执行语句中间进行导入。
if(a > 0){ let b = require('./work.js') }
这个时候 b
输出的是 a
输出值的拷贝。这个时候,模块内部的变化就影响不到 b
的值。同时,b
值也可以在后续的使用中修改或覆盖。这里需要注意防止变量污染。
EsModule基本语法
导出
EsModules 导出分为两种,单个导出(export)
和默认导出(export default)
,单个导出
跟 commonJs
不同,commonJs
是导出的全部值都一起导入,而 EsModules
是可以选择导入的值。默认导出(export default)
则是全部一起导入。
// 单个导出,可导出多个 export const num = 11 export const words = 'Hello World!'
// 默认导出 export default { say() { console.log('Yeah!') }, num: 11 }
单个导出
与 默认导出
可混合使用,但需要注意导入时,需要先导入默认导出
,再导入单个导出
。
// dog.js export const owner = 'xiaoA' export default { name: 'puppy', say(){ console.log('汪汪') } } // index.js import dog, { owner } from './dog.js' console.log(owner) // xiaoA console.log(dog.name) // puppy dog.say() // 汪汪
导入
EsModules
使用 import
语法进行导入,单个导入
需要使用花括号导入 { }
// 单个导出 // a.js export const num = 11 export const words = 'Hello World!' import { num, words } from './a.js' console.log(num) // 11 console.log(words) // Hello World! // 如果都是单个导出,可以使用以下方法全部导入 import * as a from './a.js' console.log(a) // { num:11, words: 'Hello World!'}
export
导出导入是值的引用,这点与 commonJs
不同,引入的值是只读状态,不能进行修改。
同时,EsModule
只能在文件的最顶端导入,不能动态引入。如果动态引入则会报错。
if(a > 0){ import b from './b.js' // 报错 }
CommonJs和EsModule的不同
CommonJs
和 EsModules
都是为了将 JavaScript
程序拆分为可单独导入的模块机制。不过它们在使用上还是有所不同。
EsModules
主流浏览器已基本兼容,而CommonJs
则需要搭配webpack
等工具才能上浏览器CommonJs
可以在代码执行时动态加载,而EsModules
不可以动态加载,必须声明在文件顶部CommonJs
导出值是拷贝值,可进行修改,而EsModules
是引用值,不能进行修改