CJS的module.exports 、 exports和ESM export default和 export详解

webpackg公共源码

js 复制代码
function __webpack_require__(moduleId) {
  if (__webpack_module_cache__[moduleId]) {
    return __webpack_module_cache__[moduleId].exports;
  }
  var module = __webpack_module_cache__[moduleId] = { exports: {} };
  __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  return module.exports;

}

结合源码分析以下问题:

  1. commonjs同时有 module.exports 、 exports 的情况 输出的一直都是 module.exports 导出的内容 ,exports 不生效

    分析:这里简化一下代码,可以结合require方法导入的函数,可以看到module.exports赋值后

    module.exports指向了新的变量,这里和第二个参数已经不是同一个对象了,后面exports.xx只是对临时变量进行赋值,并没有什么意义

    解决办法:

    1.统一用exports

    2.用module.exports,需要格外添加module.exports.xxx=value

    js 复制代码
    var __webpack_modules__ ={
        "./src/util/math.ts":(module, exports)=>{
            module.exports ={
                sum,
                sub
            }
            exports.sumM = sum;
    		exports.subM = sub,
        }
    }
    • 1.esModule(后面简称ESM)模块用commonJS(简称CJS)的reqiure导入后会多包了一层default
    • 2.ESM export default导出从另一个模块导入后不能直接解构赋值,
    js 复制代码
    // esModule导出,主要代码
    export const formattedDate2 = (date: Date) => {
      return date;
    };
    
    export default {
      formattedDate,
      formattedDate2,
    }
    //index.js
    
    import esModule, { formattedDate2 } from "./util/format";
    // const { formattedDate } = esModule;
    console.log("esModule", esModule, formattedDate2);

    同样的简化源码

    js 复制代码
     var __webpack_modules__ ={
        "./src/util/format.ts":(__unused_webpack_module, __webpack_exports__, __webpack_require__)=>{
          __webpack_require__.d(__webpack_exports__, {
          	"default": () => (__WEBPACK_DEFAULT_EXPORT__),
            formattedDate2,
          })
            const __WEBPACK_DEFAULT_EXPORT__ = ({
                formattedDate: formattedDate,
                formattedDate2: formattedDate2
            })
        }
    }
    
      var _util_format__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(./src/util/format.ts");
                                                                          
    console.log("esModule", _util_format__WEBPACK_IMPORTED_MODULE_0__["default"], _util_format__WEBPACK_IMPORTED_MODULE_0__.formattedDate2)

    这里注意 直接导入的是获取_util_format__WEBPACK_IMPORTED_MODULE_0__["default"],而解构赋值是直接调用的_util_format__WEBPACK_IMPORTED_MODULE_0__这就是两者 export default 和 export的区别

    js 复制代码
    //ESM 特有
     __webpack_require__.d = function (exports, definition) {
        for (var key in definition) {
          if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
            Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
          }
        }
      };
    
    // hasOwnProperty() 方法返回一个布尔值,表示对象自有属性(而不是继承来的属性)中是否具有指定的属性
      __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }

    再看 __webpack_require__.d函数对Module执行了什么操作,通过Object.defineProperty给exports分别声明default和formattedDate2 属性 的getter方法 和声明该属性可枚举。

    注意这里没有导出setter方法,所以是不能直接修改导出的变量的,但是我们可以在模块导出setter方法去修改变量(我个人觉得有点像私有变量)。

    js 复制代码
    // esModule增加如下导出,
    let value = "old";
    const setName = (newValue: string) => {
      value = newValue;
    };
    
    export { value, setName };
    //编译的源码如下
    __webpack_require__.d(__webpack_exports__, {
        "default": () => (__WEBPACK_DEFAULT_EXPORT__),
         formattedDate2: () => formattedDate2,
        setName: () => setName,
        value: () => value
    }

这里回过头看问题就清晰了,问题一require导出ESM模块的默认导出一致(看的webpack教程说以前不一样,可能是webpack5修改的),问题2同上,默认导出的是default属性不能直接解构赋值的

import * as namespace "./moduleName"和import defalueModule from "./moduleName"的区别

  • import * as namespace from "./moduleName:这种方式使用了命名空间导入。它将整个 module库导入到一个名为 namespace 的命名空间中。也就是说包含export default和export所有导出内容

  • import echarts from 'echarts':这种方式直接导入了 echarts 库的默认导出(export default)

相关推荐
keyipatience6 分钟前
JS学习笔记(2)数组,函数,作用域,对象
前端·javascript·笔记·学习·html
2603_965148118 分钟前
商品价格监控 API 接口:从原理到实战的完整指南
java·前端·数据库·python·生活
donk131415 分钟前
React Native for OpenHarmony 实战:三方库 react-native-segmented-control-tab 的鸿蒙化适配指南
javascript·react native·react.js·华为·harmonyos
酷虎软件20 分钟前
视频加字幕怎么制作
java·前端·音视频
Geoffwo30 分钟前
robotjs0.6.0鼠标中轴滚动失效修复方案
前端·javascript
彭亚川Allen40 分钟前
从零手搓 RAG 之文档解析技术
前端·后端·架构
oicola1 小时前
Ant Design v5 vs Tailwind CSS:组件库与样式框架的终极对决
前端·css
溪语流沙1 小时前
【Web全栈进阶】Vue Router + Pinia:SPA路由与全局状态
前端·javascript·vue.js
ManageEngineITSM1 小时前
工单优先级怎么定?影响×紧急度矩阵的设计与落地方法
java·大数据·运维·前端·数据库·变更管理
智商网输送线配件1 小时前
电子制造零散耗材补货实战:小批量混批采购平台怎么选才不停机?
大数据·服务器·前端·数据库·自动化