【js 知识】Commonjs 和 Es Module 的对比

前端Javascript模块化 CommonJS与ES Module区别 ES Module 的静态结构支持编译时删除未使用代码(如 Webpack 的 Tree Shaking),而 CommonJS 因动态加载无法实现此优化。ES Module的普及促使npm生态向ESM迁移,工具链(如Webpack、Rollup、Vite)全面支持ESM,形成从开发到构建的完整解决方案。从“脚本堆砌”到“工程化设计”,模块化推动了组件化开发、Monorepo架构和微前端实践,例如通过Webpack和Vite实现模块联邦与即时编译。模块化通过独立作用域隔离变量,避免全局命名冲突。 阅读详情

前言

今天简单学习下模块化的知识,准备跳槽面试的同学可以看起来了,基础打牢,啥都不怕了

模块化

  • 模块化的意义是将程序划分成一个一个小的模块结构,每个模块有属于自己小世界,不会影响到其他的结构
  • 没有模块化可能造成全局污染,引入多个 js 文件,可能出现同样命名的方法
  • 没有模块化,依赖管理也是一个难以处理的问题

commonjs

  • 模块同步加载并执行模块文件,拷贝一份值出来
common 变量
  • module 当前模块信息
  • require 引入模块的方法
  • exports 导出模块的属性
require
模块导入规则
  • ./ 和 …/ 相对路径的文件模块, / 绝对路径的文件模块,会被当作文件模块处理,require() 方法会将路径转换成真实路径* 没有路径开头则视为导入一个包* fs、http、path 等标识符,为 nodejs 的核心模块,将被优先处理* 不是核心模块 会从当前文件的同级目录的 node_modules 寻找 -> package.json 下 main 属性指向的文件 -> index.js ,index.json ,index.node* 如果再没有,在父级目录的 node_modules 查找,一直递归到根目录下的 node_modules,直到找不到为止结束
缓存
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存* 每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性* 代码分析```
    function require(id) {const cachedModule = Module._cache[id];// 模块是否被加载过,加载过则取出来走缓存if (cachedModule) {return cachedModule.exports;}const module = { exports: {} ,loaded: false , …}// 对模块进行缓存Module._cache[id] = module// 这一步执行文件内容// 为 true 则加载完成,返回对象module.loaded = truereturn module.exports
    }

##### 循环引用

// a 文件
exports.a = 1;
const b = require(‘./b’);
console.log(b);
exports.a = 2;
// b 文件
exports.b = 3;
const a = require(‘./a’);
console.log(a);
exports.b = 4;
// app 文件
const a = require(‘./a’);
console.log(a);


* 代码流程分析1.执行 app.js 代码,获取 require('./a') -> 无缓存 ->加入缓存 -> 执行模块2.执行 require('./b') -> 无缓存 -> 加入缓存执行模块,进行 b -> require('./a') -> 有缓存,直接读取 -> 回到 b.js3.打印 { a: 1 } -> 执行 exports.b = 4,修改 b 等于 44.回到 a.js -> b 获取完毕,打印 { b: 4 } -> 执行 exports.a = 2,修改 a 为 25.回到 app.js -> 获取 a 完毕,输出 { a: 2 }

#### module.exports 和 exports

##### exports

* 正确写法

// a 模块
exports.name = ‘breeze’;
exports.age = ‘18’;
exports.fun = function () {console.log(‘bao’);
};

// app.js 文件引用
const a = require(‘./a’);
console.log(a); // { name: ‘breeze’, age: ‘18’, fun: [Function] }


* 错误写法:不能直接赋值

// 上文 a.js 修改成如下写法
exports = {name: ‘breeze’,age: ‘18’,fun: function () {console.log(‘bao’);},
};

// app.js 文件引用
const a = require(‘./a’);
console.log(a); // { }


* 错误原因:exports、module、require 都是通过形参的方式传入到模块中,如果直接 exports 新赋值一个对象的话,改变了引用类型的地址
* 模拟一下函数的流程

// js 代码中写的内容
const script = const a = require('./a');module.exports = function say() {return {a: a,};};;

// 通过参数的形式传入函数,所以不能改变引用对象的地址,否则只能输出为空
function wrapper(script) {return ‘(function (exports, require, module, __filename, __dirname) {’ + script + ‘\n})’;
}

// 执行包装函数
const modulefunction = wrapper(script);


##### module.exports

* 和 exports 是同一个引用地址* 支持的写法,可以放在一个对象里```
module.exports = {name: 'breeze',age: '18',fun: function () {console.log('bao');},
}; 
  • 不同的是 module.exports 可以直接赋值,不导出对象,以下情况生效
module.exports = '1';
module.exports = [1, 2, 3];
module.exports = function () {}; //导出方法 

Es Module

  • 提前加载并执行模块文件
  • 在预处理阶段分析依赖关系,在执行阶段执行模块(深度优先遍历,执行顺序先子后父)
  • ES6 模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块
import、export
  • 引入和导出都是静态的,import 自动提升至顶层* import、export 不能放在块级作用域或条件语句中* 不可以在导入的文件中修改,可以在导出的文件中操作,可以理解为无论是否基本类型都是进行的引用传递
// a 文件
export let count = 1;
export addCount = () => {count++
}

// app 文件
import { count, addCount } from './a'
count = 2 // 报错,不可以修改
addCount() // 可以正常修改 
import()
  • import() 返回 Promise 对象
  • 可以进行动态使用
// a 文件
export name = 'breeze';
export default function fun () {console.log('bao')
}

// app 文件
setTimeout(() => {import('./a').then(res=>{console.log(res) // { name: 'breeze', default: f fun() }})res
}, 0); 
  • 经常使用于路由加载:react 路由懒加载
import React, { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';

const dynamicImport = (dirName: string) => {const Module = lazy(() => import(`../pages/${dirName}`)); // 动态加载return <Module />;
};

export const Router = () => {return (<Routes><Route path="/todo" element={dynamicImport('todo')} /></Routes>);
};

export default () => {return (<Suspense fallback={loading}><Router /></Suspense>);
}; 
tree shaking
  • tree shaking 原理就是利用的 es6 的 import、export,用来尽可能的删除没有被使用过的代码,不进行打包
// a 文件
export count = 1;
export const addCount = () => {count++
}
export const reduceCount = () => {count--
}

// app 文件
import { addCount } from './a'
addCount() 
  • 以上引用 reduceCount 将不被打包,因为并没有使用到

两者区别

  • CommonJs 的导出是拷贝一份变量出来,ES6 Module 导出的是变量是引用类型的,不能随意更改
  • CommonJs 是可以写在判断里的动态语法,ES6 Module 需要先进行静态分析
  • CommonJs 只能导出单个值,ES6 Module 导出的值数量不限制

最后,整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

关于JavaScript、TypeScript Module的配置和用法 JavaScript模块 的配置和用法 阅读详情

相关推荐

AB相增量式编码器以及STM32定时器编码器模式测速/测距离(HAL库)

编码器(Encoder)是一种用于测量旋转运动或位置的设备。编码器通常与定时器模块一起使用,以便在微控制器中获取和计算旋转的脉冲数量,从而确定物体的运动方向和距离。编码器在许多应用中都很有用,例如机器人运动控制、电机位置反馈和位置传感。STM32微控制器提供了多种类型的编码器支持,其中一种常见的编码器类型是增量编码器。增量编码器基于两个脉冲信号通道,通常称为A相和B相。当旋转发生时,这两个信号通道的相位关系会发生变化,从而可以计算出旋转方向和旋转的步数。

嵌入式软件工程师的博客 1万+

commonJs 和 esModule 的区别

commonJs 和 esModule 的区别 commonJs是被加载的时候运行,esModule是编译的时候运行 commonJs输出的是值的浅拷贝,esModule输出值的引用 commentJs具有缓存。在第一次被加载时,会完整运行整个文件并输出一个对象,拷贝(浅拷贝)在内存中。下次加载文件时,直接从内存中取值 ...

weixin_44616890的博客 519

用deepseek对GPU服务器进行压力测试

利用 DeepSeek 模型对 GPU 服务器进行压力测试,核心思路是通过,验证 GPU 服务器在计算、显存、网络等维度的承载能力,同时观察稳定性与性能瓶颈。

weixin_42795092的博客 1610

CommonJS 与 ES6模块化写法对比

1、为什么要模块化? 为了防止引入多个js文件, 产生全局变量污染, 出现冲突的情况 可维护性强,复用性高 2、CommonJS 导出 引入 module.exports={ } require() 注意:导出只能导出一个对象,一个js文件就是一个对象 eg:导出 引入: 3、ES6 导出 引入 export import 注意:ES6可以导出多个值 eg:导出 引入: 注意: 导出的格式是import { } form 和export对应的单词 imp

qq_49353940的博客 303

基于Python的MGWR多尺度地理加权回归模型

多尺度地理加权回归(MGWR)变量之间的关系在地理空间上不是均一的,所有特征变量的影响都在不同的空间范围(带宽)内变化,某些变量可能表现出局部性影响(小带宽),某些变量可能表现出全局性影响(大带宽),通过优化每个特征变量的带宽,捕捉到空间关系的多尺度特性,得到更细致的模型解释。

weixin_61965078的博客 3855

HC-SR04测距不准?STM32F103定时器捕获模式详解与精度提升实战

本文详细解析了HC-SR04超声波测距模块在STM32F103上的精度问题,并提供了定时器输入捕获模式的实战配置方法。通过硬件级时间测量和温度补偿算法,将测距精度提升至±0.1cm,适用于工业级应用场景。文章包含完整的代码实现和测试对比数据,帮助开发者解决超声波测距不准的常见问题。

weixin_30313409的博客 351

CommonJS和ES6模块有什么区别

commonjs和esmodule有什么区别

weixin_50786692的博客 1650

Transformer实战(32)——Transformer模型压缩

在本节中,我们学习了如何在硬件资源受限的情况下减轻运行大模型的负担。我们介绍了如何通过蒸馏、剪枝和量化从训练好的模型中提取高效模型。预训练轻量级的通用语言模型(如 DistilBERT) 可以在各种任务上进行微调,并表现出与非蒸馏模型相当的性能。随着数据量的不断增加,我们希望模型能够更快地运行,在这方面,高效 Transformer 起着至关重要的作用。

盼小辉丶的博客 2591

CommonJS模块和ES模块的定义及区别

这段时间在开发用nodejs写的后端,是个很老的项目,node版本是10.X.X。。。习惯性的用import导入模块,发现项目报错才反应过来想到面试的时候也经常会被问到这个问题,属于典型的前端八股文范畴,正好遇到了,就稍微整理一下吧,自己的理解,不对的地方请大佬指正。

qq_58151324的博客 847

卷积码Viterbi译码算法原理及C语言实现

具体而言,卷积码的编码过程是将输入数据和编码器中的状态进行异或操作,输出码字为各个状态对应的结果。Viterbi译码算法是一种最大似然译码算法,根据接收到的含有噪声的码字,寻找出最有可能的原始数据序列。(2) 递推计算:根据接收到的码字和当前状态,计算下一时刻各个状态的路径度量,并记录每个状态的前驱状态。以上代码实现了一个简单的卷积码Viterbi译码算法,通过接收到的码字进行译码,并输出解码结果。(1) 初始化:将所有状态的路径度量初始化为一个很大的值,选择路径度量最小的状态作为起始状态。

2301_79331421的博客 826

R语言中的Gamma分布函数

在R语言中,我们可以使用最大似然估计(Maximum Likelihood Estimation,MLE)或最小二乘估计(Least Squares Estimation,LSE)等方法来估计Gamma分布的参数。本文介绍了在R语言中使用Gamma分布函数的基本操作,包括生成随机变量、计算概率密度函数和累积分布函数,以及参数估计和拟合。函数来生成Gamma分布的随机变量,计算概率密度函数(PDF)和累积分布函数(CDF),以及进行参数估计和拟合。要计算Gamma分布的累积分布函数(CDF),我们可以使用。

ByteWhiz的博客 1633

CommonJs 和 ESModule 的 区别整理

1. exports 和 module.exports 的区别 module.exports 默认值为{} exports 是 module.exports 的引用 exports 默认指向 module.exports 的内存空间 require() 返回的是 module.exports 而不是 exports 若对 exports 重新赋值,则断开了 exports 对 module.exports 的指向 引用: require 和 import 都可引用 //foo.js expor

风华绝代的博客 2401

YOLOv8改进 | 卷积模块 | 用DWConv卷积替换Conv【轻量化网络】

YOLOv8改进,yolov8,yolov8创新,yolov8涨点

kay_545 7159

【NodeJS】浅析 exports 与 module.exports 的区别 及 export default 与 export 的区别

模块的概念   模块分为两类:原生模块和文件模块。原生模块即 Node.js API 提供的原生模块,原生模块在启动时已经被加载。文件模块为动态加载模块,加载文件模块的工作主要由原生模块 module 来实现和完成。原生模块在启动时已经被加载,而文件模块则需要通过调用 Node.js 的 require 方法来实现加载。   需要了解的一点是,Node.js 会对原生模块和文件模块都进行缓存,...

bjzhaoxiao的专栏 328

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JS模块化

将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起;块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信;CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD CMD解决方案;AMD规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅;

weixin_42683639的博客 1467

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

JavaScript里面的模块化4种方式(CommonJS,AMD,CMD,es6Module)

JS的模块化大致有CommonJS,AMD,CMD,es6Module四种。那么它们到底有什么相同和不同之处呢? CommonJS CommonJS:在Node中使用,同步加载模块。在esModule还没有出现时,为Node主要模块化解决方案。 导入: const moduleA = require("./modulePath") const { moduleB } = require("./modulePath") 导出: module.exports = moduleA // 默认模块 modu

Czuaphe的博客 1514

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

前端基础知识——module

Module -module Sets the module system for the program. See theModulesreference page for more information. You very likely want"CommonJS"for node projects. ChangingmoduleaffectsmoduleResolutionwhichalso has a reference page. Here’s some example ...

fy959fy的博客 1021

webpack学习2.1 模块化开发(JS模块化&CSS模块化)

一.JS模块化 命名空间,COMMONJS,AMD/CMD/UMD,ES6 module 1.什么是命名空间 库名.类别名.方法名 弊端:在命名空间重复生命,要记住完整的路径名(而且很长) var NameSpace = {} NameSpace.type = NameSpace.type || {} //已经定义了就是它自己,没有定义就赋值一个空对象给它,避免命名空间覆...

努力学习的肥宅 211

聊聊CommonJS与ES6 Module的使用与区别

学了JS并且用过Node.js后,对模块化应该是有所了解和使用了,那么一定见过以下两种模块导入导出的方式第一种: ES6 Module;第二种: CommonJS

零一的博客 7541

Commonjs 和 Es Module详解

今天我们来深度分析一下Commonjs和Es Module,希望通过本文的学习,能够让大家彻底明白Commonjs和Es Module原理,能够一次性搞定面试中遇到的大部分有关Commonjs和Es Module的问题。1 Commonjs 和 Es Module 有什么区别?2 Commonjs 如何解决的循环引用问题?3 既然有了exports,为何又出了?既生瑜,何生亮?4require模块查找机制?5 Es Module 如何解决循环引用问题?6这种写法为何无效?7 关于。

weixin_66128399的博客 4514

JavaScript模块化演进:从CommonJS到ES Module的全面解析

JavaScript模块化演进:从CommonJS到ES Module的全面解析

嗨,欢迎来到我的 优快云 博客小天地!一名深耕多年的技术发烧友。在这里,我将把日常工作中积累的宝贵经验,从复杂架构设计的精妙之处,到代码优化的实战技巧,毫无保留地分享给大家。 3984

CommonJS与ES6 Module的使用与区别

CommonJS是2009年由JavaScript社区提出的包含了模块化的一个标准,后来被Node.js所采用并实现,也就是说我们在Node.js中用到的模块导入导出都是依照CommonJS标准来实现的。

qq_36760651的博客 1946

js - CommonJs和ES6 module的使用和区别

CommonJs和ES6 module的使用和区别

尽日寻春不见春,芒鞋踏遍陇头云。归来笑拈梅花嗅,春在枝头已十分。 2441

JS中的几种模块化规范(CommonJS、AMD、CMD、ES6 Module)

引入问题:为什么要进行模块化? 1)模块化就是将系统分离成独立功能的模块,这样我们需要什么功能,就加载什么功能 2)模块化的好处: 避免命名空间的冲突(减少命名空间的污染) 更好的分离,实现按需加载 提高可代码的复用性 提高了代码的维护性 JS模块化大致发展过程 CommonJS(服务端)=》AMD(浏览器)=》CMD=》ES6 Module模块化 模块化规范的种类 模块化规范的发展趋势 终极:现代工具webpack webpack自己实现了一套模块机制,无论是CommonJs模块的require

Amelian的博客 3483

ES Module 和 CommonJS的区别

前端项目:优先使用 ES Module,配合工程化工具实现树摇和优化。Node.js 项目:新项目推荐 ES Module(“type”: “module”),旧项目兼容 CommonJS。需动态加载模块(如根据条件导入):可在 ESM 中使用 import() 函数(返回 Promise,支持动态加载),兼具静态分析和动态能力。

m0_75112012的博客 964

深入浅出 JavaScript 的模块化:从 CommonJS 到 ES Modules

同步 vs 异步:CommonJS 是同步加载模块,适合服务器端使用;而 ES6 模块支持异步加载,适合现代浏览器的使用场景。静态 vs 动态:ES6 模块支持静态分析,可以进行更好的优化(如 tree-shaking);CommonJS 主要通过动态的require加载模块。默认导出:CommonJS 使用进行默认导出,而 ES6 模块使用。模块化是 JavaScript 发展过程中不可或缺的一个特性,从 CommonJS 到 ES6 模块,模块化的实现方式不断演进,带来了更高效、更灵活的开发体验。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 2102
上一篇: 【Flutter】解决多级列表嵌套滑动冲突方案选择
下一篇: 【VUE】用nodejs快速搭建简易的mock数据服务器
梅花十三儿
博客等级 码龄5年 1038粉丝 444原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值