CommonJS

CommonJS 是由 JavaScript 社区于 2oo9 年提出的包含模块、文件、IO、控制台在内的一系列标准。Node.js 的实现中采用了 CommonJS 标准的一部分,并在其基础上进行了一些调整。我们所说的 CommonJS 模块和 Node.js 中的实现并不完全一样,现在一般谈到 CommonJS 其实是 Node.js 中的版本,而非它的原始定义。

CommonJS 最初只为服务端而设计,直到有了 Browserify ——一个运行在 Node.js 环境下的模块打包工具,它可以将 CommonJS 模块打包为浏览器可以运行的单个文件。这意味着客户端的代码也可以遵循 CommonJS 标准来编写了。

不仅如此,借 Node.js 的包管理器,npm 开发者还可以获取他人的代码库,或者把自己的代码发布上去供他人使用。这种可共享的传播方式使 CommonJS 在前端开发领域逐渐流行起来。

模块

通过 script 标签插入的 JS 文件的顶层作用域是全局作用域,在进行变量及函数声明时会污染全局环境:而通过 CommonJS 引入的 JS 文件会形成一个属于模块自身的作用域,所有的变量及函数只有自己能访问,对外是不可见的。请看下面的例子:

//calculator.js
var name = 'calculator.js';
//index.js
var name = 'index.js';
require('./calculator.js');
console.log(name); // index.js

这里有两个文件,在 index.js 中我们通过 CommonJS 的 require 函数加载 calculator.js。运行之后控制台结果是 “index.js”,说明 calculator.js 中的变量声明并不会影响 index.js,可见每个模块是拥有各自的作用域的。

导出

导出是一个模块向外暴露自身的唯一方式。在 CommonJS 中,通过 module.exports 可以导出模块中的内容,如:

module.exports = {name: 'calculater'add: function(a, b){return a + b;}
}

CommonJS 模块内部会用一个 module 对象存放当前模块的信息,可以理解成在每个模块的最开始定义了以下对象:

var module = {//...};
// 模块自身逻辑
module.exports = {//...};

module.exports 用来指定该模块要对外暴露哪些内容,为了书写方便,CommonJS 也支持另种简化的导出方式——直接使用 exports:

exports.name = 'calculater';
exports.add = function(a,b){return a + b;
}

其内在机制是将 exports 指向 module.exports,而 module.exports 在初始化时是一个空对象。我们可以简单地理解为,CommonJS 在每个模块的首部默认添加了以下代码:

var module = {exports: {}
};
var exports = module.exports;

但不能直接给 exports 赋值,否则会导致其失效。还有禁止将 module.exports 和 exports 混用。

导入

在 CommonJS 中使用 require 语法进行模块导入。如:

// calculator.js
module.exports = {	add: function(a, b){return a + b;}
}
// index.js
const calculator = require('./calculator.js');
const sum = calculator.add(2, 3);
console.log(sum); // 5

当我们使用 require 导入一个模块时会有两种情况:

  • 该模块未曾被加载过。这时会首先执行该模块,然后获取到该模块最终导出的内容。
  • 该模块已经被加我过。这时该模块的代码不会再次执行,而是直接获取该模块上一次导出的内容。

我们前面提到,模块会有一个 module 为象用来存放其信息,这个对象中有一个属性 loaded 用于记录该模块是否被加载过。loaded 的值默认为 false ,在模块第一次被加载和执行过后会置为true,后面再次加载时检查到 module.loadedtrue ,则不会再次执行模块代码。

有时我们加载一个模块,不需要获取其导出的内容,只是想要通过执行它而产生某种作用,比如把它的接口挂在全局对象上,此时直接使用 require 即可。

require('./task.js');

模块封装器

在执行模块代码之前,Node.js 将使用如下所示的函数封装器对其进行封装:

(function(exports, require, module, __filename, __dirname) {// Module code actually lives in here
}); 

通过这样做,Node.js 实现了以下几点:

  • 它将顶层变量(使用 varconstlet 定义)保持在模块而不是全局对象的范围内。
  • 它有助于提供一些实际特定于模块的全局变量,例如:
    • moduleexports 对象,实现者可以用来从模块中导出值。
    • 便利变量 __filename__dirname,包含模块的绝对文件名和目录路径。

模块作用域

__dirname

当前模块的目录名。这与 __filenamepath.dirname() 相同。

__filename

当前模块的文件名。这是当前模块文件的已解析符号链接的绝对路径。对于主程序,这不一定与命令行中使用的文件名相同。

在这里插入图片描述

exports

module.exports 的引用,其输入更短。

在这里插入图片描述

直接给 module.exportsexports 赋值都会断开引用关系。

在这里插入图片描述

在这里插入图片描述

直接赋值会导致以下后果:

在这里插入图片描述

moudle

当前模块的引用,请参阅关于 module 对象的部分。特别是,module.exports 用于定义模块导出的内容,并通过 require() 使其可用。

require(id: string)

  • id —— 模块名称或路径
  • 返回值—— 模块导出的内容

用于导入模块、JSON 和本地文件。模块可以从 node_modules 导入。可以使用相对路径(例如 ././foo./bar/baz../foo)导入本地模块和 JSON 文件,该路径将根据 __dirname(如果有定义)命名的目录或当前工作目录进行解析。

require.cache

  • 第一次加载某个模块时,Node 会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的 module.exports 属性(不会再次执行该模块)。
  • 如果需要多次执行模块中的代码,一般可以让模块暴露行为(函数)。
  • 模块的缓存可以通过 require.cache 拿到,也可以从此对象中删除键值,下一次 require 将重新加载模块。

在这里插入图片描述

require.main

Module 对象代表 Node.js 进程启动时加载的入口脚本,如果程序的入口点不是 CommonJS 模块,则为 undefined。参见访问主模块。

在这里插入图片描述

require.resolve(request[, options])

  • request —— 要解析的模块路径。
  • options
    • paths 从中解析模块位置的路径。如果存在,将使用这些路径而不是默认解析路径,但 GLOBAL_FOLDERS$HOME/.node_modules 除外,它们始终包含在内。这些路径中的每一个都用作模块解析算法的起点,这意味着从此位置检查 node_modules 层级。

在这里插入图片描述

require.resolve.paths(request)
  • request—— 正在检索其查找路径的模块路径。
  • 返回一个数组,其中包含在解析请求期间搜索的路径,如果请求字符串引用核心模块,例如 httpfs,则返回 null

在这里插入图片描述

moudle 对象

在每个模块中,module 自由变量是对代表当前模块的对象的引用。module 实际上不是全局的,而是每个模块本地的。

在这里插入图片描述

module.children

此模块首次需要的模块对象。

在这里插入图片描述

module.exports

从模块中导出任何你想导出的东西。
在这里插入图片描述

赋值给 module.exports 必须立即完成。不能在任何回调中完成。以下不起作用:

在这里插入图片描述

exports

参考 模块作用域->exports

module.filename

模块的完全解析文件名。

在这里插入图片描述

module.id

模块的标识符。通常这是完全解析的文件名。

在这里插入图片描述

module.isPreloading

如果模块在 Node.js 预加载阶段运行,则为 true

在这里插入图片描述

module.loaded

模块是否已完成加载,或正在加载。

在这里插入图片描述

module.parent

第一个需要此模块的模块,如果当前模块是当前进程的入口点,则为 null;如果该模块是由非 CommonJS 模块加载的模块(例如:REPL 或 import),则为 undefined

在这里插入图片描述

module.path

模块的目录名称。这通常与 module.idpath.dirname() 相同。

在这里插入图片描述

module.paths

模块的搜索路径。

在这里插入图片描述

module.require(id)

  • id —— 模块名称或路径
  • 返回值—— 模块导出的内容

module.require() 方法提供了一种加载模块的方法,就像从原始模块调用 require() 一样。为了做到这一点,有必要获取对模块对象的引用。由于 require() 返回 module.exports,并且该模块通常仅在特定模块的代码中可用,因此必须显式导出才能使用。

在这里插入图片描述

在这里插入图片描述

基本上,用 module.requrie 是极少见的,借用它家的 module 更为少见。

module.builtinModules

Node.js 提供的所有模块的名称列表。可用于验证模块是否由第三方维护。

注意:列表不包含像 node:test 这样的仅前缀模块。

此上下文中的 module 与模块封装器提供的对象不同。要访问它,需要 Module 模块:

// import { builtinModules } from 'node:module' // es模块
const builtin = require('node:module').builtinModules;

在这里插入图片描述

module.createRequire(filename)

  • filename —— 用于构造 require 函数的文件名。必须是文件网址对象、文件网址字符串、或绝对路径字符串。
  • 返回 —— require 函数。

在这里插入图片描述

module.isBuiltin(moduleName)

  • moduleName —— 模块名称。
  • 返回:—— 如果模块是内置的,则返回 true,否则返回 false

在这里插入图片描述

module.register(specifier[, parentURL] [, options])

  • specifier: <string>|<URL> —— 需要注册的定制钩子;这应该与传递给 import() 的字符串相同,但如果它是相对的,则它是相对于 parentURL 解析的。
  • parentURL: <string>|<URL> —— 如果你想要相对于基本 URL(例如 import.meta.url)解析 specifier,你可以在此处传递该 URL。默认值:'data:'
  • options: <Object>
    • parentURL: <string>|<URL> —— 如果你想要相对于基本 URL(例如 import.meta.url)解析 specifier,你可以在此处传递该 URL。如果 parentURL 作为第二个参数提供,则忽略此属性。默认值:'data:'
    • data: <any> —— 传递到 initialize 钩子的任何任意的、可克隆的 JavaScript 值。
    • transferList: <Object[]> —— 可转换对象 要传递到 initialize 钩子中。

注册一个导出钩子的模块,用于自定义 Node.js 模块解析和加载行为。参见定制钩子

module.syncBuiltinESMExports()

module.syncBuiltinESMExports() 方法,用于更新所有内置 ES 模块的实时绑定,以匹配 CommonJS 模块的exports属性。这个方法的主要目的是为了协调 CommonJS 和 ES6 模块之间的交互,确保在使用混合模块系统时,数据的同步和一致性。

此外,这个方法还涉及到对内置模块的修改和同步。虽然内置模块在运行时可以被修改,但不能新增或删除。通过module.syncBuiltinESMExports(),可以确保这些修改被正确地同步到整个模块系统中,保持数据的一致性和完整性。

在这里插入图片描述

确定模块系统

当传递给 node 作为初始输入时,或者当被 import 语句或 import() 表达式引用时,Node.js 会将以下内容视为ES 模块

  • 扩展名为 .mjs 的文件。
  • 当最近的父 package.json 文件包含值为 "module" 的顶层 "type" 字段时,扩展名为 .js 的文件。
  • 字符串作为参数传入 --eval,或通过 STDIN 管道传输到 node,带有标志 --input-type=module
  • 使用 --experimental-detect-module 时,包含语法的代码仅成功解析为ES 模块,例如 importexport 语句或 import.meta,没有明确标记应如何解释它。显式标记是 .mjs.cjs 扩展、带有 "module""commonjs" 值的 package.json "type" 字段,或者 --input-type--experimental-default-type 标志。CommonJS 或 ES 模块都支持动态 import() 表达式,并且不会导致文件被视为 ES 模块。

当传递给 node 作为初始输入时,或者当被 import 语句或 import() 表达式引用时,Node.js 会将以下内容视为CommonJS

  • 扩展名为 .cjs 的文件。
  • 当最近的父 package.json 文件包含值为 "commonjs" 的顶层字段 "type" 时,则扩展名为 .js 的文件。
  • 字符串作为参数传入 --eval--print,或通过 STDIN 管道传输到 node,带有标志 --input-type=commonjs

除了这些明确的情况之外,还有其他情况,Node.js 根据 --experimental-default-type 标志的值默认使用一个模块系统或另一个模块系统:

  • 如果同一文件夹或任何父文件夹中不存在 package.json 文件,则以 .js 结尾或没有扩展名的文件。
  • 如果最近的父 package.json 字段缺少 "type" 字段,则以 .js 结尾或没有扩展名的文件;除非该文件夹位于 node_modules 文件夹内。(当 package.json 文件缺少 "type" 字段时,无论 --experimental-default-type 如何,为了向后兼容,node_modules 下的包范围始终被视为 CommonJS。)
  • 当未指定 --input-type 时,字符串作为参数传递给 --eval 或通过 STDIN 通过管道传递给 node

该标志当前默认为 "commonjs",但将来可能会更改为默认为 "module"。因此,最好尽可能明确;特别是,包作者应始终在其 package.json 文件中包含 "type" 字段,即使在所有源都是 CommonJS 的包中也是如此。如果 Node.js 的默认类型发生变化,显式说明包的 type 将使包面向未来,它还将使构建工具和加载器更容易确定应如何解释包中的文件。

启用

Node.js 有两个模块系统:CommonJS 模块和 ECMAScript 模块

默认情况下,Node.js 会将以下内容视为 CommonJS 模块:

  • 扩展名为 .cjs 的文件;
  • 当最近的父 package.json 文件包含值为 "commonjs" 的顶层字段 "type" 时,则扩展名为 .js 的文件。
  • 当最近的父 package.json 文件不包含顶层字段 "type" 或任何父文件夹中都没有 package.json 时,具有 .js 扩展名或不带扩展名的文件;除非该文件包含错误的语法,除非它被评估为 ES 模块。包作者应该包括 "type" 字段,即使在所有源都是 CommonJS 的包中也是如此。明确包的 type 将使构建工具和加载器更容易确定包中的文件应该如何解释。
  • 扩展名不是 .mjs.cjs.json.node.js 的文件(当最近的父 package.json 文件包含值为 "module" 的顶层字段 "type" 时,这些文件将被识别为 CommonJS 模块只有当它们是通过 require() 包含,而不是用作程序的命令行入口点时)。

有关详细信息,请参阅确定模块系统

调用 require() 始终使用 CommonJS 模块加载器。调用 import() 始终使用 ECMAScript 模块加载器。

访问主模块

当文件直接从 Node.js 运行时,则 require.main 被设置为其 module。这意味着可以通过测试 require.main === module 来确定文件是否被直接运行。

对于文件 foo.js,如果通过 node foo.js 运行,则为 true,如果通过 require('./foo') 运行,则为 false

当入口点不是 CommonJS 模块时,则 require.mainundefined,且主模块不可达。

在这里插入图片描述

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

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

相关文章

android java 用系统弹窗的方式实现模拟点击动画特效

接上一篇&#xff1a;android java系统弹窗的基础模板-CSDN博客 本篇记录的是系统弹窗的一个应用示例&#xff1a;实现点击动画效果 首先模拟点击的实现参考&#xff1a;android模拟点击_motionevent upevent motionevent.obtain(systemclo-CSDN博客 动画效果&#xff0c;是…

基于最近邻数据进行分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt# 生成一个简单的数据…

[SAP ABAP] ABAP SQL跟踪工具

事务码ST05 操作步骤 步骤1&#xff1a;使用事务码ST05之前&#xff0c;将要检测的程序生成的页面先呈现出来&#xff0c;这里我们想看下面程序的取数操作&#xff0c;所以停留在选择界面 步骤2&#xff1a; 新建一个GUI窗口&#xff0c;输入事务码ST05&#xff0c;点击 Acti…

算法的时间复杂度

什么是时间复杂度&#xff1f; 算法的时间复杂度是算法的执行效率 算法的执行时间和算法输入值之间的关系&#xff0c;与函数中代码的执行次数有关。 常见的时间复杂度案例分析&#xff1a; O(1) 算法的执行时间和输入值无关 O(logn) 算法的执行时间和代码的执行次数呈log…

蓝桥杯备考:高精度算法之除法

我们除法的高精度其实也不完全是高精度&#xff0c;而是一个高精度作被除数除以一个低精度 模拟我们的小学除法 由于题目中我们的除数最大是1e9&#xff0c;当它真正是1e9的时候&#xff0c;t是有可能超过1e9的&#xff0c;所以要用long long

重新刷题求职2-DAY1

DAY1 1.704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 最普通的二分查找&#xff0c;查用的习惯左闭右…

算法竞赛(Python)-堆栈

文章目录 一 基础知识二 题目有效的括号字符串解码 一 基础知识 堆栈&#xff08;Stack&#xff09;&#xff1a;简称为栈。一种线性表数据结构&#xff0c;是一种只允许在表的一端进行插入和删除操作的线性表。   我们把栈中允许插入和删除的一端称为 「栈顶&#xff08;top…

SpringBoot 中的测试jar包knife4j(实现效果非常简单)

1、效果图 非常快的可以看见你实现的接口 路径http://localhost:8080/doc.html#/home 端口必须是自己的 2、实现效果 2.1、导入jar包 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-jakarta-spring-boot-star…

16.1.STM32F407ZGT6-CAN基础概念

参考&#xff1a; https://blog.csdn.net/sunlight_vip/article/details/128639144 前言&#xff1a; 学习总结CAN的知识点&#xff1a; 1.can是什么&#xff0c;历史由来和背景 2.can的物理层&#xff0c;链路层 3.初始化的流程和关键点 4.波特率怎么设置 5.can id怎么过滤 6…

Linux环境下的Java项目部署技巧:Nginx 详解

Nginx 的启动 Nginx 启动会生成 2 个进程&#xff1a;主进程与守护进程 主进程&#xff1a;常用于提供反向代理服务。特点&#xff1a;占内存大守护进程&#xff1a;防止主进程以外关闭。特点&#xff1a;占内存小 Nginx 启动需要占用 80 端口: 当 Ngnix 启动失败时&#xff0…

【Pytorch和Keras】使用transformer库进行图像分类

目录 一、环境准备二、基于Pytorch的预训练模型1、准备数据集2、加载预训练模型3、 使用pytorch进行模型构建 三、基于keras的预训练模型四、模型测试五、参考 现在大多数的模型都会上传到huggface平台进行统一的管理&#xff0c;transformer库能关联到huggface中对应的模型&am…

relational DB与NoSQL DB有什么区别?该如何选型?

Relational Database(关系型数据库,简称RDB)与NoSQL Database(非关系型数据库)是两类常见的数据库类型。它们在设计理念、数据存储方式、性能优化、扩展性等方面有许多差异。下面我们将会详细分析它们的区别,以及如何根据应用场景进行选型。 一、数据模型的区别 关系型…

Flutter常用Widget小部件

小部件Widget是一个类&#xff0c;按照继承方式&#xff0c;分为无状态的StatelessWidget和有状态的StatefulWidget。 这里先创建一个简单的无状态的Text小部件。 Text文本Widget 文件&#xff1a;lib/app/app.dart。 import package:flutter/material.dart;class App exte…

智能小区物业管理系统推动数字化转型与提升用户居住体验

内容概要 在当今快速发展的社会中&#xff0c;智能小区物业管理系统的出现正在改变传统的物业管理方式。这种系统不仅仅是一种工具&#xff0c;更是一种推动数字化转型的重要力量。它通过高效的技术手段&#xff0c;将物业管理与用户居住体验紧密结合&#xff0c;无疑为社区带…

给AI加知识库

1、加载 Document Loader文档加载器 在 langchain_community. document_loaders 里有很多种文档加载器 from langchain_community. document_loaders import *** 1、纯文本加载器&#xff1a;TextLoader&#xff0c;纯文本&#xff08;不包含任何粗体、下划线、字号格式&am…

游戏引擎 Unity - Unity 设置为简体中文、Unity 创建项目

Unity Unity 首次发布于 2005 年&#xff0c;属于 Unity Technologies Unity 使用的开发技术有&#xff1a;C# Unity 的适用平台&#xff1a;PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域&#xff1a;开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…

CSS Display属性完全指南

CSS Display属性完全指南 引言核心概念常用display值详解1. block&#xff08;块级元素&#xff09;2. inline&#xff08;行内元素&#xff09;3. inline-block&#xff08;行内块级元素&#xff09;4. flex&#xff08;弹性布局&#xff09;5. grid&#xff08;网格布局&…

浅谈知识蒸馏技术

最近爆火的DeepSeek 技术&#xff0c;将知识蒸馏技术运用推到我们面前。今天就简单介绍一下知识蒸馏技术并附上python示例代码。 知识蒸馏&#xff08;Knowledge Distillation&#xff09;是一种模型压缩技术&#xff0c;它的核心思想是将一个大型的、复杂的教师模型&#xff0…

小红的小球染色期望

B-小红的小球染色_牛客周赛 Round 79 题目描述 本题与《F.R小红的小球染色期望》共享题目背景&#xff0c;但是所求内容与范围均不同&#xff0c;我们建议您重新阅读题面。 有 n 个白色小球排成一排。小红每次将随机选择两个相邻的白色小球&#xff0c;将它们染成红色。小红…

ASP.NET Core与配置系统的集成

目录 配置系统 默认添加的配置提供者 加载命令行中的配置。 运行环境 读取方法 User Secrets 注意事项 Zack.AnyDBConfigProvider 案例 配置系统 默认添加的配置提供者 加载现有的IConfiguration。加载项目根目录下的appsettings.json。加载项目根目录下的appsettin…