【模块化】 js 模块化(CommonJS, AMD, UMD, CMD, ES6)

news2024/12/24 2:29:01

目录

  • js 的演变
  • 模块化
    • 1. CommonJS 规范
      • commonJs伪代码
      • ⭐CommonJS优缺点
    • 2. AMD 规范
      • ⭐AMD 优缺点
    • 3. UMD 规范
      • ⭐UMD = AMD + CommonJS
    • 4. CMD 规范
      • ⭐CMD 优缺点
    • 5. ES6 模块化
    • 符号绑定
      • ⭐ESM 优缺点
  • AMD 和 CMD 的区别
  • ES6 模块与 CommonJS 模块的差异
  • 参考

将介绍几种 js 模块化的规范,以及它们各自的优缺点和差异…

js 的演变

在 js 刚出现的时候,只是作为脚本语言,但随着浏览器的不断发展,js 越来越被重视起来,可以实现较为复杂的功能。这个时候开发者为了维护方便,会把不同功能的模块抽离出来写入单独的 js 文件,但是当项目更为复杂的时候,html 中可能会引入很多个 js 文件,而这个时候就会出现命名冲突,污染作用域等一系列问题,这个时候 模块化 的概念及实现方法应运而生。

模块化

模块化开发是一种管理方式,一种生产方式,也是一种解决问题的方案。一个模块就是实现某个特定功能的文件,我们可以很方便的使用别人的代码,想要什么模块,就引入那个模块。但是模块开发要遵循一定的规范,后面就出现了我们所熟悉的一系列规范
在这里插入图片描述

1. CommonJS 规范

CommonJS 主要用在 node 开发上,每个文件就是一个模块,每个文件都有自己的一个作用域。通过module.exports 暴露 public 成员。
此外,CommonJS 通过 require 引入模块依赖,require 函数可以引入 node 的内置模块、自定义模块和 npm 等第三方模块。

commonJs伪代码

在这里插入图片描述
在这里插入图片描述
参考文章

定义模块:

// 定义模块 math.js
var basicNum = 0;
function add(a, b) {
  return a + b;
}
// 在这里写上需要向外暴露的函数、变量
module.exports = { 
  add: add,
  basicNum: basicNum
}

加载模块:

// 引入 math.js 模块
var math = require('./math');
math.add(2, 3); // 5

⭐CommonJS优缺点

优点:

  1. 简单并且容易使用
  2. 服务器端模块便于重用

缺点:

  1. 同步的模块加载方式不适合在浏览器环境
  2. 不能非阻塞的并行加载多个模块

2. AMD 规范

AMD 是 (Asynchronous Module Definition) 的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行
在 AMD 规范中,我们使用 define 定义模块,使用 require 加载模块,但是不同于 CommonJS,它要求两个参数:

定义模块:

define(id?, dependencies?, factory);
  • id 是定义的模块名,这个参数是 可选的,如果没有定义该参数,模块名字应该默认为模块加载器请求的指定脚本的名字,如果有该参数,模块名必须是顶级的绝对的。
  • dependencies 是定义的模块中所依赖的 模块数组,也是 可选的,依赖模块优先级执行,并且执行结果按照数组中的排序依次以参数的形式传入 factory。
  • factory 是模块初始化要执行的函数或对象,是 必需的。

加载模块:

require([module], callback);

第一个参数 module,是一个数组,里面的成员就是要加载的模块;第二个参数 callback,则是加载成功之后的回调函数。如果将前面的 CommonJS 改写成 AMD 形式,就是下面这样:

require(['./math'], function (math) {
  math.add(2, 3);
});

⭐AMD 优缺点

优点:

  1. 适合在浏览器环境中异步加载模块
  2. 可以并行加载多个模块

缺点:

  1. 提高了开发成本
  2. 不符合通用的模块化思维方式

3. UMD 规范

UMD 是 (Universal Module Definition) 通用模块定义 的缩写。UMD 是 AMD 和 CommonJS 的一个糅合
AMD 是浏览器优先,异步加载;CommonJS 是服务器优先,同步加载。
既然要通用,怎么办呢?
那就先判断是否支持 node 的模块,支持就使用 node;
再判断是否支持 AMD,支持则使用 AMD 的方式加载。
这就是所谓的 UMD。

⭐UMD = AMD + CommonJS

示例:

(function (window, factory) {
  if (typeof exports === "object") {
    // CommonJS
    module.exports = factory();
  } else if (typeof define === "function" && define.amd) {
    // AMD
    define(factory);
  } else {
    // 浏览器全局定义
    window.eventUtil = factory();
  }
})(this, function () {
  // do something
});

4. CMD 规范

CMD 是 (Common Module Definition) 公共模块定义 的缩写。
CMD 可能是在 CommonJS 之后抽象出来的一套模块化语法定义和使用的标准。
在 CMD 规范中,一个模块就是一个文件。
CMD模块化方案与AMD类似,也采用异步加载模块的方式,但是它更加注重模块的依赖关系,可以更好地管理模块之间的依赖关系。
而CMD是懒加载,虽然会一开始就并行加载js文件,但是不会执行,而是在需要的时候才执行。
CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写,依赖延迟执行

// cmd1.js
define(function(require,exports,module){
    // ...
    module.exports={
        // ..
    }
})// cmd2.js
define(function(require,exports,module){    
    var cmd2 = require('./cmd1') 
    // cmd2.xxx 依赖就近书写
    module.exports={
        // ...
    }
})
seajs.use(['cmd2.js','cmd1.js'],function(cmd2,cmd1){
  // ....
})

定义模块:

define(factory);

define 接收 factory 参数,它可以是一个函数,也可以是一个对象或一个字符串。

  • 当 factory 是一个对象或是一个字符串时,表示该模块的接口就是这个对象或者字符串。

  • 当 factory 是一个函数时,表示是该模块的构造方法执行该构造方法,可以得到模块向外提供的接口。factory 在执行时,默认传入三个参数:require、exports、module。
    其中 require 用来加载其它模块,exports 用来向外提供模块接口
    module 是一个对象,存储着与当前模块相关联的一些属性和方法。

加载模块:
我们可以通过 SeaJs 的 use 方法加载模块:

seajs.use([module], callback);

⭐CMD 优缺点

优点:可以很容易在 node 中运行
缺点:依赖 SPM 打包,模块的加载逻辑偏重

5. ES6 模块化

ES6 模块的设计思想是尽量的 静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
在 ES6 中,我们使用 export 关键字来导出模块,使用 import 关键字来引入模块

引入模块:

// ES6模块
import { stat, exists, readFile } from 'fs';

上面代码实质是从 fs 模块中加载 3 个方法,其他方法不加载。
这种加载称为 “编译时加载” 或者 静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。
当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。

导出模块:

let firstName = 'Zhou';
let lastName = 'ShuYi';
let year = 1994;
export { firstName, lastName, year };

上面代码在 export 后面,使用大括号指定所要输出的一组变量。export 除了输出变量,还可以输出函数或类。

符号绑定

是因为ESM会开辟一块名为模块环境记录内存空间用来实时绑定导出变量,模块环境记录中的数据是以const常量声明无法修改值或改变内存地址
一旦导出文件修改导出变量,会删除模块环境记录中对应数据并重新生成新的常量。(所以值改变了)
被引用的值,指向同一块内存空间:

在这里插入图片描述
普通函数:
在这里插入图片描述
ESM中:
在这里插入图片描述
ESM中的符号绑定

⭐ESM 优缺点

优点:容易进行静态分析
缺点:原生浏览器端还没有实现该标准

AMD 和 CMD 的区别

对于依赖的模块,AMD 是 提前执行,CMD 是 延迟执行。

AMD 推崇 依赖前置,CMD 推崇 依赖就近。

AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。

ES6 模块与 CommonJS 模块的差异

  1. CommonJS 模块输出的是一个 值的拷贝,ES6 模块输出的是 值的引用

  2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

  3. CommonJS 模块的 require() 是 同步加载 模块,ES6 模块的 import 命令是 异步加载,有一个独立的模块依赖的解析阶段。

  4. CommonJs导入的模块路径可以是一个表达式,因为它使用的是require()方法;而ES6 Modules只能是字符串

  5. CommonJS this指向当前模块,ES6 Modules this指向undefined

  6. 且ES6 Modules中没有这些顶层变量argumentsrequiremoduleexports__filename__dirname

参考

参考文章
参考文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1305193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mirrors and reflections for VR

专为虚拟现实而建,但也非常适合非虚拟现实桌面和移动项目 这是URP管道,从Unity2019.4.16一直测试到2023年。 完全工作场景预览,轻松修改着色器材质。着色器支持折射,可以制作很酷的效果。 镜子/反射可以互相反射,而不仅仅是2...想象一下一个电梯,3面镜子都互相反射,直到…

【清晰明了】Jenkins邮件发送配置

自带邮件插件 首先要知道的是jenkins是自带邮件插件的,且不支持卸载。 下面开始配置自带邮件插件。 配置默认邮件管理员 系统管理 --> 系统配置,进行如下配置: 不配置管理员邮件地址报错如下 jakarta.mail.internet.AddressException:…

论文阅读二——基于全脸外观的凝视估计

论文阅读二——基于全脸外观的凝视估计 基础知识主要内容文章中需要学习的架构AlexNet 代码复现 该论文是2017年在CVPR中发表的一篇关于 “gaze estimation” 的文章,其论文地址与代码地址如下: 论文地址 代码地址 论文特点:文章提出了一种…

Java进阶 1-1 枚举

目录 枚举的基本特性 枚举类型中的自定义方法 switch语句中的枚举 编译器创建的values()方法 使用实现代替继承 构建工具:生成随机的枚举 组织枚举 EnumSet EnumMap 本笔记参考自: 《On Java 中文版》 枚举类型通过enum关键字定义,其…

【Spring进阶系列丨第五篇】详解Spring中的依赖注入

文章目录 一、说明二、构造函数注入2.1、方式一【index索引方式】2.1.1、定义Bean2.1.2、主配置文件中配置Bean2.1.3、测试 2.2、方式二【indextype组合方式】2.2.1、定义Bean2.2.2、主配置文件配置Bean2.2.3、测试2.2.4、解决方案 2.3、方式三【name方式】2.3.1、定义Bean2.3.…

5. PyTorch——数据处理模块

1.数据加载 在PyTorch中,数据加载可通过自定义的数据集对象。数据集对象被抽象为Dataset类,实现自定义的数据集需要继承Dataset,并实现两个Python魔法方法: __getitem__:返回一条数据,或一个样本。obj[in…

unity Mesh Simplify 1.10(模型优化工具:查看面数,降低面数灯)

提示:文章有错误的地方,还望诸位大神不吝指教! 文章目录 前言一、面板参数详解说明二、使用方法总结 前言 有时候想对模型优化一下,奈何又不会建模方面的。虽然我感觉它的数值不大对,但是不影响我们优化顶点数嘛。 Me…

LeetCode 1631. 最小体力消耗路径:广度优先搜索BFS

【LetMeFly】1631.最小体力消耗路径:广度优先搜索BFS 力扣题目链接:https://leetcode.cn/problems/path-with-minimum-effort/ 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (ro…

【玩转TableAgent数据智能分析】TableAgent全功能详解及多领域数据分析实践(中)不同领域数据分析实践

3 电影点评数据分析实践 利用本身自带的电影点评数据,来具体看一下TableAgent的分析能力,选择电影点评数据,智能体会自动导入该数据DMSC20000.csv,大小为3.3 MB。在数据信息展示区,就会显示出该数据,并提供…

你一定要知道的Fiddler过滤器 Filters 详解

如果要对当前Fiddler的抓包进行过滤(如过滤掉与测试项目无关的抓包请求),那功能强大的 Filters 过滤器能帮到你。 进入 Filters 选项页,勾选上 Use Filters,即启用过滤器。 Actions 四个选项说明: Run Fi…

SI24R03 高度集成低功耗SOC 2.4G 收发一体芯片

今天给大家介绍一款Soc 2.4G 收发一体模块-SI24R03 Si24R03是一款高度集成的低功耗无线SOC芯片,芯片为QFN32 5x5mm封装,集成了资源丰富的MCU内核与2.4G收发器模块,最低功耗可达1.6uA,极少外围器件,大幅降低系统应用成本…

(第8天)保姆级 PL/SQL Developer 安装与配置

PL/SQL Developer 安装与配置(第8天) 咱们前面分享了很多 Oracle 数据库的安装,但是还没有正式使用过 Oracle 数据库,怎么连接 Oracle 数据库?今天就来讲讲我学习中比较常用的 Oracle 数据库连接工具:PL/SQL DEVELOPER。 PL/SQL Developer 的安装和配置对于新手来说还是…

机器学习---Boosting

1. Boosting算法 Boosting思想源于三个臭皮匠,胜过诸葛亮。找到许多粗略的经验法则比找到一个单一的、高度预 测的规则要容易得多,也更有效。 预测明天是晴是雨?传统观念:依赖于专家系统(A perfect Expert) 以“人无…

【Qt信号槽源码分析】

Qt信号槽源码分析 一、相关宏介绍二、示例moc文件源码解析信号发送接收过程源码解析emit signalconnect 三、关键类图:四、时间&空间问题五、总结 一、相关宏介绍 *要使用信号-槽功能,先决条件是继承QObject类,并在类声明中增加Q_OBJECT…

ue5材质预览界面ue 变黑

发现在5.2和5.1上都有这个bug 原因是开了ray tracing引起的,这个bug真是长时间存在,类似的bug还包括草地上奇怪的影子和地形上的影子等等 解决方法也很简单,就是关闭光追(不是…… 就是关闭预览,在材质界面preview sc…

屠宰加工污废水处理工艺设备有哪些

屠宰加工行业对于废水处理的要求日益严格,为了达到环保要求,减少对环境造成的负面影响,屠宰加工污废水处理工艺设备应运而生。以下是常见的几种工艺设备: 1. 沉淀池:沉淀池是屠宰加工废水处理中常用的处理设备之一。废…

【RTOS学习】模拟实现任务切换 | 寄存器和栈的变化

🐱作者:一只大喵咪1201 🐱专栏:《RTOS学习》 🔥格言:你只管努力,剩下的交给时间! 目录 🏀认识任务切换🏐切换的实质🏐栈中的内容🏐切…

scala表达式

1.8 表达式(重点) # 语句(statement):一段可执行的代码# 表达式(expression):一段可以被求值的代码,在Scala中一切都是表达式 - 表达式一般是一个语句块,可包含一条或者多条语句,多条语句使用“…

Fiddler如何比较两个接口请求?我来告诉你

进行APP测试时,往往会出现Android和iOS端同一请求,但执行结果不同,这通常是接口请求内容差异所致。 我习惯于用Fiddler抓包,那此时应该如何定位问题呢? 分别把Android和iOS的接口请求另存为TXT文件,然后用…

软件安全设计

目录 一,STRIDE 威胁建模 1,STRIDE 2,总体流程(关键步骤) 3,数据流图的4类元素 二,安全设计原则 三,安全属性 一,STRIDE 威胁建模 1,STRIDE STRIDE 是…