Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • React

  • Vue

  • JavaScript文章

    • new命令原理
    • ES5面向对象
    • ES6面向对象
    • 多种数组去重性能对比
    • 几个高级的JS API
    • JS随机打乱数组
    • 判断是否为移动端浏览器
    • 防抖与节流函数
    • JS获取和修改url参数
    • 比typeof运算符更准确的类型判断
    • Navigator clipboard介绍使用
    • Javascript 语法错题集
    • ESM和CommonJS详解
      • ColorThief的介绍与使用
      • 三级目录

    • 学习笔记

    • openlayers

    • threejs

    • MapboxGL

    • 工具

    • 源码合集

    • 前端
    • JavaScript文章
    东流
    2024-08-30
    目录

    ESM和CommonJS详解

    # 概述

    ESM 和 CommonJS 是前端非常常见的两种规范或模块标准,本文将重点讲述这两者的定义、适用范围以及区别。

    # ESM

    ESM即 ECMAScript Modules,是 Javascript 的官方模块化标准,旨在统一 Javascript 的模块化机制。

    # ESM 的导出和导入

    • 导出:使用 export 关键词导出模块内容,可以是命名导出或默认导出
    /** a.js */
    export const obj = () => {
      console.log(5);
    };
    
    //默认导出
    const greet = () => {
      console.log("Hello World");
    };
    export default greet;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    • 导入:使用import语法来加载模块
    /** b.js */
    import greet, { obj } from "../a.js";
    
    1
    2

    # 特点

    • 异步加载:支持异步加载,适合浏览器环境,与 Javascript 的动态加载功能兼容良好
    • 静态分析:支持静态分析,意味着在编译时可以检查模块的依赖关系,对于优化和工具链支持如tree-shaking很有帮助
    • 浏览器支持:ESM 可以直接在浏览器中使用,只需要写成<script type='module'>即可
    • 严格模式:默认在严格模式下运行

    # CommonJS

    CommonJS是一个 Javascript 模块标准,主要用于 Node.js 环境

    # 模块的导入导出

    • 导出:使用module.exports或exports对象来导出模块内容
    /** a.js */
    module.exports = () => {
      console.log("commonjs");
    };
    
    1
    2
    3
    4
    • 导入:使用require()函数来加载模块
    /** b.js */
    const greet = require("./a.js");
    greet();
    
    1
    2
    3

    # 特点

    • 同步加载:CommonJS 是同步加载的,所以模块正在代码执行时会被即时加载,这可以用SSR
    • 文件系统:CommonJS 模块依赖于 Node.js 的文件系统,因此不适用于浏览器
    • 模块缓存:CommonJS 在第一次加载模块后,会缓存模块导出的结果,因此如果后续加载相同的模块时会使用缓存,避免重复加载

    # ESM和CommonJS对比

    • ESM使用import加载模块时,必须放在文件的最顶部,而CommonJS使用require则没有这个限制
    • ESM规范对应的标准文件后缀名是.mjs,而CommonJS则是.cjs

    # 符号绑定(Live Binding)

    ESM中有个Live Binding的概念,有的人称之为符号绑定。在开发中,定义的变量在程序编译之后都会被转化为地址,而执行变量就是符号。所谓的符号绑定就是将程序中使用到的变量名等,换成对应的地址,方便查找相应的数据。

    前面提到ESM是在编译阶段就可以确定好模块间的依赖关系,因此对于变量也可以在这个时间进行确定地址,进行替换,这就是静态绑定。

    而CommonJS是运行时,它不存在符号绑定这个概念,因此只有在程序运行时进行地址查找和替换,这就称为动态绑定。

    举例说明: ESM

    /** a.mjs */
    export const obj = {
      number: 0,
    };
    
    const add = () => {
      obj.number += 1;
    };
    
    export default add;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /** b.mjs */
    import es, { obj } from "./a.mjs";
    
    es();
    console.log("🚀 ~ es:", es, obj);
    
    1
    2
    3
    4
    5

    CommonJS

    /** a.cjs */
    const obj = {
      number: 0,
    };
    
    const add = () => {
      obj.number += 1;
    };
    
    module.exports = { add, obj };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /** b.cjs */
    const { add, obj } = require("./a.cjs");
    
    add();
    console.log("🚀 ~ add:", add, obj);
    
    1
    2
    3
    4
    5

    分别定义导出文件a.mjs、a.cjs和导入文件b.mjs、b.cjs,通过执行node b.mjs和node b.cjs,得到如下结果:

    这说明无论是ESM还是CommonJS,都会进行内存地址共享,引用的是同一个数据

    编辑 (opens new window)
    上次更新: 2024/09/01, 03:20:02
    Javascript 语法错题集
    ColorThief的介绍与使用

    ← Javascript 语法错题集 ColorThief的介绍与使用→

    最近更新
    01
    GeoJSON
    05-08
    02
    Circle
    04-15
    03
    CircleMarker
    04-15
    更多文章>
    Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式