前言
之前看过一篇CJS与ES6的导入导出文章,发现自己看不懂,平时项目上都是基础的导入导出使用,根本没考虑其中的细节,导致有没有写过bug自己也不知道。此文记录一下使用时的注意点。
CommonJS
- 运行时加载,同步加载;模块被多次引入时,会缓存,最终只加载(运行)一次;
- 有
exports
与module.exports
两种导出方式,最终导出的是module.exports
而不是exports
,所以当exports
和module.exports
都存在时以后者为准; exports
也能导出的内部实现原理: module.exports = {}; exports = module.exports- 导出的是值,不是引用;导出的对象在其它文件中导入后,可以修改对象中的属性值;
下面来个小demo展示一下,通过打印发现导出的是值,age属性打印值变为30是因为obj对象是一个引用地址。
有次有个后端同事问我下面这两种引用方式,为啥可以使用方式一样,且打印内容一样:
const ethers = require('./module.js')
// const {ethers} = require('./module.js')
console.log(ethers.thing);
console.log(ethers.obj);
这个问题大家可以先自己思考一下如何实现,我感觉是这样的,添加了一个自引用:
ES6
- 编译时加载,异步加载;
- 有
export
和export default
两种导出方式,export
可以导出多次,export default
只能导出一次;
注意点一:export
后面的{}不是表示的一个对象,export {name: name}
是错误写法,如下图使用直接报错。import后面的{}也不是一个对象,里面只是存放导入的标识符列表内容。但是export default
后面的{}是一个对象。
注意点二:在导出导入时起别名可以使用as
:
export { name as fName, age as fAge } // 导出时起别名
import { name as fName, age as fAge, foo as fFoo } from './foo.js' // 导入时起别名
注意点三:原生JS使用模块化,需要在script
标签中添加type="module"
。然后直接在浏览器中运行会报错,因为直接加载html
文件会遇到cors
错误,不能以file
协议打开es module
的代码,会报错,需要用http
协议访问。可以在vscode中通过右键live server(vscode安装的一个插件)在浏览器中运行。
// 加入一个属性type="module",就表示该文件以module方式运行,会自动加入一个async属性,即es module是异步的
<script src="./index.js" type="module"></script>
注意点四:导出的到底是值还是引用。
export
导出,导出的是引用,基础类型也是引用;export default
导出,导出的是值,不是引用;但是在值中的对象,还是引用地址;export default
导出中的特例:export defalut function fn() {}
,函数以这种方式导出时导出的是引用而不是值;
注意点五:导入的是值还是引用。
- 导入方式中,除
let {} = await import()
外均为引用; - 上述方法导入的为引用类型,这个不难理解,对导入的对象进行了解构赋值;
注意点六:导出导出结合使用时,到底导入的是值还是引用呢。
- 导出与导入均为引用时,最终导入的才是引用;
案例:给出一个demo,自己试着打印最终结果:
最终结果为:
ES6比CommonJS更推荐使用
网上资源找到的一些解释:
- JavaScript 捆绑包的大小仍然是导致浏览器应用程序变慢的头号原因;
- commonJS让捆绑包更大,参考文章:https://web.dev/commonjs-larger-bundles/;
- CommonJS 是 2009 年的标准,最初并没有打算用在 Web 浏览器上,主要用于服务器端应用程序,所以CommonJS 在设计时没有考虑减少生产包的大小。为确保捆绑程序能够成功优化您的应用程序,避免依赖 CommonJS 模块,并在整个应用程序中使用 ECMAScript 模块语法。
我自己理解的ECMAScript比CommonJS更推荐使用的原因:
- 感觉是因为CommonJS模块是一个动态加载过程,导致如webpack的Terser和Tree Shaking等无法更好的代码优化处理;
- webapck是一个静态打包工具,而ECMAScript是静态编译加载的,默认支持webpack的各种优化配置;