深入浅出前端模块化原理

前言

什么是模块化

模块化简单说就是为了解决代码没有自己的"域",很容易造成命名冲突,依赖混乱。我们的代码通过模块化按照一定的规范和方式进行划分和组织,以便于模块的复用、维护和管理。

模块化解决方案

从最开始的通过立即执行函数(IIFE)到 CJS、AMD、CMD、UMD、再到 ES6 引入模块化 ESM,本文主要写 CJS 和 ESM。

CommonJs

实现原理

我们先创建两个文件

src/index.js

js 复制代码
const name = require("./name")  
console.log(name)  

src/name.js

js 复制代码
var name = "john";  
module.exports = {  
    name: name,  
}  

我们把以上代码打包,通过产物看一下 CJS 到底是如何进行模块化的。产物代码经过简化

从产物中不难看出 CJS 把每个路径的源码都存在一起,然后通过 require 来实现读取并缓存,实现模块化的功能,其实说到底还是使用了立即执行函数(IIFE)来实现的。

EsModule

我们在 name.js 加上默认导出。

js 复制代码
// src/name.js  
export var name = "john";  
export default "this is default"  

ESM 和 CJS 的区别在于,ESM 给 exports 做了一层代理。

当我们使用 ESM 导入的值,实际上都是代理值,我们每次访问这个值其实都是通过要这个代理,这也就是为什么导出后改变这个值,导入的文件也能拿到更新后的值。

扩展

设置值类型

在 EsModule 的 __webpack_modules__ 中有一个方法 __webpack_require__.r 这个是干什么用的呢?他其实就是把 exports标记成 Module 类型。

我们判断一个值的属性,通过 Object.prototype.toString.call()方法,那么这个方法是根据什么判断出类型的?其实就是根据值的 Symbol.toStringTag 来识别。

举个例子:

js 复制代码
const obj = {};  
Object.defineProperty(obj, Symbol.toStringTag, {value: "Module"});  
console.log(Object.prototype.toString.call(obj)); // [object Module]  

CJS 和 ESM 区别

CJS ESM
语法类型 动态 静态
加载方式 运行时加载 编译时加载
加载行为 同步加载 异步加载
this指向 当前模块 undefined
能否修改 可以修改引用的值 引入的值是只读的
引用 基本类型复制 引用类型浅拷贝 动态只读引用
书写位置 任意位置 顶层

运行时加载和编译时加载

运行时加载会生成一个对象全部加载,运行时获得该对象。编译时加载直接从模块中加载,能做到按需加载,效率更高。

相关推荐
爬虫练习生2 分钟前
极验4ast解混淆流程
javascript
踩着两条虫9 分钟前
AI + 低代码实战 | 一文吃透 API 管理、Swagger 导入与全局配置
前端·低代码·ai编程
AI自动化工坊10 分钟前
T3 Code:专为AI编程代理设计的Web IDE技术实践指南
前端·ide·人工智能·ai编程·t3
梦梦代码精14 分钟前
LikeShop 深度测评:开源电商的务实之选
java·前端·数据库·后端·云原生·小程序·php
Mr.E515 分钟前
odoo18 关闭搜索框点击自动弹出下拉框
开发语言·前端·javascript·odoo·owl·odoo18
鹏程十八少18 分钟前
4. 2026金三银四 Android OkHttp 面试核心 45 问:从源码到架构深度解析
android·前端·面试
invicinble20 分钟前
前端技术栈--webpack
前端·webpack·node.js
天籁晴空23 分钟前
微信小程序 静默登录 + 授权登录 双模式配合的设计方案
前端·微信小程序·uni-app
|晴 天|25 分钟前
Vue 3 博客 SEO 优化:Meta 标签、Sitemap、Schema.org 实战
前端·vue.js·dreamweaver
Apple_羊先森26 分钟前
# MOSS-TTS-Nano 教程 02:CLI 与 Web Demo 实战
前端·人工智能