前言
之前看过一篇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')
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安装的一个插件)在浏览器中运行。
<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的各种优化配置;
|