Node.js入门 03:模块化规范 CommonJS 与 ES Module

2023-11-18

目的

传统的用在网页中的JavaScript代码文件与文件之中的内容都是全局相互可见的,这对于大型项目特别是多人合作的项目来说挺不好的,容易互相影响,出现各种问题。

大多数编程语言都有类库、模块等概念来处理这个问题,在Node.js中早期是使用CommonJS规范来处理这个问题。后来JavaScript的ES6标准中制定了ES module规范,所以Node.js也渐渐的开始支持ES module规范了。

这篇文章将对这两种模块化方式做个简单的使用说明。

CommonJS

基础使用

CommonJS规范模块使用上主要就三点:

  • 每个文件就是一个模块,有自己的作用域,其中的变量、函数等都是私有的,对其他文件不可见;
  • 可以使用 module.exports 导出当前模块中的变量、函数等,供其它文件使用;
  • 其它文件中使用 require() 方法引入模块;

下面是个简单的例子:

// common.js
let name = 'naisu'
module.exports.name = name // 导出name变量
module.exports.fun = function(){ // 导出函数
    console.log('233~');
}
// test.js
const cm = require('./common.js') // 导入模块

console.log(cm.name) 
cm.fun()

在这里插入图片描述
上面例子可以看到CommonJS规范模块导入导出使用都很简单。对于模块而言所有要导出的东西整体就是一个对象,挂在module.exports上;其它文件中用 require() 方法导入模块其实就是导入了模块的module.exports上的对象。
在这里插入图片描述

module 对象

CommonJS规范中每个模块内部,都有一个module对象代表当前模块,它有以下属性:

module.id 模块的识别符,通常是带有绝对路径的模块文件名;
module.filename 模块的文件名,带有绝对路径;
module.loaded 返回一个布尔值,表示模块是否已经完成加载;
module.parent 返回一个对象,表示调用该模块的模块;
module.children 返回一个数组,表示该模块要用到的其他模块;
module.exports 表示模块对外输出的值;

上面属性中最重要的就是 module.exports 了,就像前面所描述的所有要导出的东西整体就是一个对象,挂在module.exports上。

在Node.js中提供了一个 exports 变量,该变量指向 module.exports ,也就是你可以使用 exports 来代替 module.exports ,但要注意的是不能使用 exports = ... 这种方式赋值,因为 exports 的内部实现其实可以理解为 var exports = module.exports

require() 方法

CommonJS规范中 require() 方法用于导入模块,导入放入可以向前面例子中 require('./common.js') 也可以写成 require('./common') ,两者效果是一样的。

require() 导入时可以使用相对路、绝对路径,或者也可以不带路径。在不带路径的情况下,程序运行时会从Node.js安装目录、项目的node_modules文件夹、用户的node_modules文件夹、系统node_modules文件夹等依次寻找该模块。

要注意的是 require() 导入模块生成的是一份拷贝,一旦一个值导出后模块内部的变化就不会影响到这个值了:
在这里插入图片描述

使用 require() 导入模块后会缓存该模块,下次再加载该模块会直接从缓存中取出。所有缓存保存在 require.cache 中,可以使用 delete require.cache[moduleName] 方法删除缓存:
在这里插入图片描述
上面的 require.resolve() 方法用于将模块解析到绝对路径。

ES Module

在JavaScript的ES6标准中加入了模块功能,通常被成为ES Module(或ES6 Module),这和前面的CommonJS有一个非常大的不同点:CommonJS中的模块只是从代码层面来实现,本质其实是个对象,ES Module是从语言层面制定的,原生的功能在性能、调试、编译等方面都有优势。

目前Node.js(v14.17.6)中虽然已经支持ES Module,但是使用起来还不是很舒服。想要使用ES Module的话得稍作处理,主要有两种方式(二选一):

  • ES模块和使用ES模块模块的文件名后缀都改为 .mjs
  • 项目文件夹中建立 package.json 文件,设置其中type字段 { "type": "module" } ,注意使用该方式后CommonJS模块文件名后缀就得改为 .cjs 了;

ES Module使用上和CommonJS差不多:

  • 每个文件就是一个模块;
  • 使用 export 导出;
  • 使用 import 导入;

下面是个简单的例子:

// module.mjs
let name = 'naisu'
function fun() {
    console.log('fun 233~')
}
class MC {
    constructor() {
        console.log('MC 233~')
    }
}
export { name, fun, MC }

// 下面代码等同于上面
// export let name = 'naisu'
// export function fun() {
//     console.log('fun 233~')
// }
// export class MC {
//     constructor() {
//         console.log('MC 233~')
//     }
// }
// test.mjs
import { name, fun, MC } from './module.mjs'

console.log(name)
fun()
let mc = new MC()

在这里插入图片描述

ES Module中 import 可以使用 * 代表模块整体、使用 as 来重命名,所以可以有下面用法:

// module.mjs
let name = 'naisu'
function fun() {
    console.log('fun 233~')
}
export { name, fun}
// test.mjs
import * as esm from './module.mjs'
console.log(esm.name)
esm.fun()

在这里插入图片描述
模块在输出的时候可以有一个默认输出,使用 export default 修饰,可以用来修饰匿名函数。在import这个默认输出的时候需要指定一个名字。参考下面例子:

// module.mjs
let name = 'naisu'
function fun() {
    console.log('fun 233~')
}
export { name }
export default fun
// test.mjs
import ff, {name} from './module.mjs'
console.log(name)
ff()

在这里插入图片描述
ES Module中导出与导入是动态绑定的关系,通过相关的接口还是可以修改内部的值的。这点和 CommonJS 有区别。

上面用 import 导入模块是静态的,会在程序运行之前导入,其实还有一个动态导入的方法 import() ,这个是异步的方法,调用时将返回一个 Promise 。使用方式可以如下:

import('./module.mjs').then((module) => {
    // TODO
});

// 也可以使用await关键字
let module = await import('./module.mjs');

混合使用

CommonJS 中使用 ES Module 可以使用 import() 方法导入:
在这里插入图片描述
ES Module 中使用 CommonJS 也只能用 import 方式整体导入:
在这里插入图片描述

更多内容可以可以参考下面文章:
阮一峰的网络日志 《Node.js 如何处理 ES6 模块》

总结

总的来说目前Node.js中的模块使用 CommonJS 规范还是最方便的,ES Module 虽然是JavaScript原生标准,但现在在Node.js中使用并不是非常顺畅,不过可以预见的是原生的 ES Module 将来大概率会完全替代现有的 CommonJS 的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js入门 03:模块化规范 CommonJS 与 ES Module 的相关文章

随机推荐

  • 2023华为OD机试真题【二元组个数/哈希表】

    题目描述 给定两个数组a b 若a i b j 则称 i j 为一个二元组 求在给定的两个数组中 二元组的个数 输入描述 第一行输入 m 第二行输入m个数 表示第一个数组 第三行输入 n 第四行输入n个数 表示第二个数组 输出描述 二元组个
  • mysql cstmt_MySQL

    创建一个以JDBC连接数据库的程序 包含7个步骤 1 加载JDBC驱动程序 在连接数据库之前 首先要加载想要连接的数据库的驱动到JVM Java虚拟机 这通过java lang Class类的静态方法forName String class
  • 《上海市居住证》签注和积分确认流程指南

    上海市居住证 签注和积分确认流程指南 一 办理条件 员工已经自行至社区事务受理服务中心办理 上海市居住证 签注 由于上海市居住地所属的社区事务中心非常多 具体申请相关流程指南及材料办理清单最好事先和居住地所属的社区事务中心确认 办理 上海市
  • SSL_CTX结构体

    定义在ssl h头文件中 struct ssl ctx st SSL METHOD method unsigned long options unsigned long mode STACK OF SSL CIPHER cipher lis
  • E-R图(Entity Relationship Diagram)实体关系模型

    E R图也称实体 联系图 Entity Relationship Diagram实体关系模型 提供了表示实体类型 属性和联系的方法 用来描述现实世界的概念模型 它是描述现实世界关系概念模型的有效方法 是表示概念关系模型的一种方式 用 矩形框
  • 为什么要用缓冲流

    一开始学习处理流会疑问为什么速度会加快呢 好比一个10KB的文件 使用最基本的字节流读写 只要读一次10KB到内存 存一次10KB到目标文件就行了 但是使用缓冲不是要读1次10KB到缓冲 再从缓冲写一次10KB到CPU 再从CPU写10KB
  • No matching distribution found for tensorflow 解决方法

    2020 8最新版本为TF2 3 安装时容易出现的问题是各软件程序版本不统一的问题 GPU版本对应表如下图所示 图片来源于Tensorflow 官网 分割线 分割线
  • 使用JavaScript编写HTML

    使用JavaScript编写HTML 1 什么是JavaScript JavaScript是一种脚本语言 通过Dom定义表示和修改文档所需的对象和这些对象的行为和属性以及这些对象之间的关系从而操作HTML文档 比如添加 移除 改变或重排页面
  • ARM之未定义指令异常和SVC异常

    异常向量表的概述 在上一章 我们学习了建立异常向量表 这里我们可以通过看arm的手册 我们每一种异常都对应一个工作模式 下面我就来尝试触发一下未定义指令异常和SVC异常 异常发生的说明 简单的来说就是先保存现场 之后恢复现场 保存现场 我们
  • 第一章 计算机系统概论

    一 计算机系统简介 1 计算机软硬件概念 计算机是一种能够执行指令的电子设备 它由硬件和软件两部分组成 计算机硬件是指计算机系统中的物理组件 包括中央处理器 CPU 内存 硬盘 输入设备 如键盘 鼠标 输出设备 如显示器 打印机 等 这些硬
  • windows10安装RDKit化学信息学python库(通过anaconda)

    RDKit是一款功能强大的化学信息学工具 推荐使用anaconda安装 安装时应当参考 1 官方安装指南 Rdkit Anaconda org 2 中文教程 RDKit简介 RDKit 中文教程 2020 09 文档 chenzhaoqia
  • python爬虫之数据解析

    python爬虫之数据解析 正则表达式 bs4 xpath 主要运用在聚焦爬虫模块中 涉及到的数据解析方法有 正则表达式 bs4以及xpath 1 使用对象 聚焦爬虫 聚焦爬虫 爬取页面中指定的页面内容 2 数据解析原理概述 解析的局部的文
  • word在另外计算机格式不对,为什么word 2007文件在不同电脑上排版显示不同?应该如何解决?...

    为什么word文件在不同电脑排版显示不同 最近打印论文 自己的笔记本是word2007 保存的通用格式 预览排版没有问题 去打印店打印时 发现插入的图片窜行了 幸亏即使调整过来 并且保存 但拿回自己的笔记本打开后图片的位置还是窜行的 请问这
  • iOS中堆和栈的使用(Swift)

    堆和栈都是一种数据项按序排列的数据结构 只能在一端 称为栈顶 top 对数据项进行插入和删除 堆 队列优先 先进先出 FIFO first in first out 栈 先进后出 FILO First In Last Out 堆栈空间分配
  • 手机APP远程温湿度监控系统(连上公网、阿里云)

    APP界面 实物图 操作演示 一 硬件电路图 这里有两点需要说明 1 第一点是关于LCD1602需不需要加上拉电阻的说明 51单片机P0口作为IO口输出时 输出低电平为0 输出高电平为高组态 并非5V 相当于悬空状态 也就是说P0 口不能真
  • 【蓝桥杯Python组】寻找2020

    寻找2020 题目描述 小蓝有一个数字矩阵 里面只包含数字 0 和 2 小蓝很喜欢 2020 他想找到这个数字矩阵中有多少个 2020 小蓝只关注三种构成 2020 的方式 同一行里面连续四个字符从左到右构成 2020 同一列里面连续四个字
  • matlab中 hold on 与 hold off,figure作用

    hold on是当前轴及图像保持而不被刷新 准备接受此后将绘制的图形 多图共存 即启动图形保持功能 当前坐标轴和图形都将保持 从此绘制的图形都将添加在这个图形的基础上 并自动调整坐标轴的范围 hold off使当前轴及图像不再具备被刷新的性
  • moviepy音视频剪辑:视频剪辑基类VideoClip详解

    前往老猿Python博文目录 一 概述 在 moviepy音视频剪辑 moviepy中的剪辑基类Clip详解 和 moviepy音视频剪辑 moviepy中的剪辑基类Clip的属性和方法详解 介绍了剪辑相关类及类关系 可以看到视频剪辑类Vi
  • 汽车电子行业静态分析和代码审查规则

    汽车电子行业静态分析和代码审查规则 查了很多编码规则大都是PDF版 最终我整理出了几份word版的 并且帮大家排版好了可直接用于书写测试大纲或报告 下载链接在我的下载中 规则包含以下 1 MISRA C 2012 2 MISRA C 200
  • Node.js入门 03:模块化规范 CommonJS 与 ES Module

    文章目录 目的 CommonJS 基础使用 module 对象 require 方法 ES Module 混合使用 总结 目的 传统的用在网页中的JavaScript代码文件与文件之中的内容都是全局相互可见的 这对于大型项目特别是多人合作的