CommonJs与ES6的导入导出细节

文章目录

  • 前言
  • CommonJS
  • ES6
  • ES6比CommonJS更推荐使用


前言

之前看过一篇CJS与ES6的导入导出文章,发现自己看不懂,平时项目上都是基础的导入导出使用,根本没考虑其中的细节,导致有没有写过bug自己也不知道。此文记录一下使用时的注意点。

CommonJS

  • 运行时加载,同步加载;模块被多次引入时,会缓存,最终只加载(运行)一次;
  • exportsmodule.exports两种导出方式,最终导出的是module.exports而不是exports,所以当exportsmodule.exports都存在时以后者为准;
  • exports也能导出的内部实现原理: module.exports = {}; exports = module.exports
  • 导出的是值,不是引用;导出的对象在其它文件中导入后,可以修改对象中的属性值;

下面来个小demo展示一下,通过打印发现导出的是值,age属性打印值变为30是因为obj对象是一个引用地址。

CommonJs与ES6的导入导出细节_第1张图片

有次有个后端同事问我下面这两种引用方式,为啥可以使用方式一样,且打印内容一样:

const ethers = require('./module.js')
// const {ethers} = require('./module.js')

console.log(ethers.thing);
console.log(ethers.obj);

这个问题大家可以先自己思考一下如何实现,我感觉是这样的,添加了一个自引用:

CommonJs与ES6的导入导出细节_第2张图片

ES6

  • 编译时加载,异步加载;
  • exportexport default两种导出方式,export可以导出多次,export default只能导出一次;

注意点一export后面的{}不是表示的一个对象,export {name: name}是错误写法,如下图使用直接报错。import后面的{}也不是一个对象,里面只是存放导入的标识符列表内容。但是export default后面的{}是一个对象。

CommonJs与ES6的导入导出细节_第3张图片

注意点二:在导出导入时起别名可以使用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,自己试着打印最终结果:

CommonJs与ES6的导入导出细节_第4张图片

最终结果为:

CommonJs与ES6的导入导出细节_第5张图片

ES6比CommonJS更推荐使用

网上资源找到的一些解释

  1. JavaScript 捆绑包的大小仍然是导致浏览器应用程序变慢的头号原因;
  2. commonJS让捆绑包更大,参考文章:https://web.dev/commonjs-larger-bundles/;
  3. CommonJS 是 2009 年的标准,最初并没有打算用在 Web 浏览器上,主要用于服务器端应用程序,所以CommonJS 在设计时没有考虑减少生产包的大小。为确保捆绑程序能够成功优化您的应用程序,避免依赖 CommonJS 模块,并在整个应用程序中使用 ECMAScript 模块语法。

我自己理解的ECMAScript比CommonJS更推荐使用的原因

  • 感觉是因为CommonJS模块是一个动态加载过程,导致如webpack的Terser和Tree Shaking等无法更好的代码优化处理;
  • webapck是一个静态打包工具,而ECMAScript是静态编译加载的,默认支持webpack的各种优化配置;

你可能感兴趣的:(js高级,node,es6,javascript,前端)