js模块化 --- commonjs规范 原理详解

news2024/9/24 3:21:33

什么是commonjs规范

        commonjs是一种模块化规范(nodejs的默认模块化规范,新版的nodejs已经支持es6的模块化,但它默认任然使用的是commonjs),通俗的说它将代码分割成了一个一个的模块,让不同的模块拥有自己独立的作用域(类似命名空间的隔断),在不同的模块中实现了重复命名的效果,同时支持模块的导入导出,让模块与模块之间可以相互调用,实现代码的复用。

tips:模块化可以让代码分离开和减少命名冲突问题,便于维护和开发,

模块化的核心:导入导出,作用域隔离

 

commonjs的导入导出

作为模块,最明显的特征就是支持导入导出,在commonjs中,使用require,module.exports,exports,来导入和导出。

const obj = {
  name: 'a',
  desc:'这是a模块'
}

module.exports = obj
const obj = {
  name: 'b',
  desc: '这是b模块'
}

module.exports = obj;
// 导入模块
const a = require('./a')
const b = require('./b')

console.log(a)
console.log(b)

以上是a,b,index模块,一个js文件就是一个模块,在a,b模块中各自有一个obj对象导出,这里就实现了模块的命名分割,在不同的模块使用声明同名的变量名。然后在index中导入并使用

7831b99c467649289621364a73fab180.png

可以看到成功的拿到了各自模块中的obj对象。

 

这就是commonjs的基本使用,接下来分析一下它的模块化原理

 

commonjs的模块化原理

为什么可以在模块(js文件)中直接使用require,和module.exports,exports进行导入导出?

从用法上看很明显,require是一个函数,它接受一个模块(js文件)路径,返回这个模块的导出的值,而module.export,export是一个对象或者变量,它用来接受值作为模块的导出;也就是说,commonjs使用一个函数进行导入,一个对象或者变量进行导出;

tips:这里分析一下导入和导出的细节,

导入:获取一个模块导出的值

导出:将模块中的值暴露出去(丢给导入) 

        

分析一下, 这个过程和函数的返回调用非常相似,在函数中,

1.你可以返回一个值作为函数的返回值(导出),

2.同时可以调用函数获取到它的返回值(导入),

3.同时在不去调用函数的情况下,外部是没有办法拿到函数内部的东西(隔离),

4.函数可以重复调用(模块也可以重复导入)

 

在commonjs中,一个模块就是一个js文件,同时,一个模块也是一个函数,到这里可能会有点疑惑,这里我们直接在任意一个模块中打印argument

console.log( arguments)

在js函数中,出来箭头函数外都有一个argument参数,它包含了这个函数调用时传入的参数

9ca64f7fae7140deb46a7feb198ba945.png

可以看到一共有5个参数,这样可以还是不够清晰,在打印一下argument的callee属性

const obj = {
  name: 'a',
  desc:'这是a模块'
}

module.exports = obj

// arguments.callee 函数本身
console.log( arguments.callee.toString())

f747e8f41fb140b5897be7a8d8d9024d.png

这下可以明显的看到在a模块的代码全都被放到了一个函数中,这个函数有5个参数exports, require, module, __filename, __dirname,这就是可以直接在模块中直接使用exports, require, module导入导出的原因。

所以在commonjs规范中,所以的js文件都作为模块,而对每一个js文件套上一层函数,是实现模块的原理,在不同的模块(函数)中,由于没有互相调用这个顶层函数,所以互相不能够访问到内部的数据。

到这里可以总结一下commonjs的原理了:

commonjs是通过给每个js文件‘外套’一层函数实现的模块化,即通过参数来导入导出,函数间作用域的隔断,函数的重复调用;但是这种模块化是基于运行时的,也就是说,虽然编译时外套了一层函数,但代码运行的时候才会进行导入导出(这很好理解,每个模块都是函数,调用模块也是在模块内调用的,函数运行了在能执行到导读导出的位置,将导出的值封装再对象中);

 

以上就是commonjs规范的模块化的原理,下面介绍一下有关commonjs的细节问题

和es6的module模块化规范的区别

这主要从以下几个方面区分:

1.ESmodule,是通过import,export,export default 进行导入导出的

2.ESmodule,是官方的规范,浏览器和node环境下都实现了对它的支持,

3.ESmodule,的模块化是基于编译时,在代码还没有执行时就已经进行了模块的导入导出,输出对应的接口,这是基于底层实现的

上面的第2点中,commonjs只支持在node环境下直接使用,浏览器种需要通过Babel进行转译才能使用,而ESmodule要在浏览器‘type = module’ 的script标签,node环境下,在package.json文件中配置,'type':'module'字段就可以使用ESmodule的规范(默认是'type':'commonjs')

 

 ESMCJS
导入导出import,export default,exportrequire,module.export,exports
实现基于编译时基于运行时

 

 

 

 

 

 

 

 有关ESmodule的使用可以参考:js模块(module)和导入,导出(import,export)_js import module-CSDN博客

导出的优先级

使用commonjs规范的导入导出时,明显注意到,导入只有require,而导出可以使用exports,和module.exports;如果同时存在这两个导出,最终会是什么结果呢?

const obj = {
  name: 'a',
  desc:'这是a模块'
}

// module.exports = obj
exports.desc = obj.desc;
exports.name = obj.name;

// arguments.callee 函数本身
// console.log( arguments.callee.toString())
const obj = {
  name: 'b',
  desc: '这是b模块'
}

module.exports = obj;

const a = require('./a')

console.log(a); // { name: 'a', desc: '这是a模块' }

411d2da585374728af219f0c73458cc3.png

a模块使用exports导出,然后在b模块导入a并运行b.js可以看到结果和module.exports的导出方法是一样的,都是将值赋给对象导出;

如果同时存在module.export和exports导出,最终会以module.exports为准,因为在commonjs实现的require函数中,最终返回的是module.exports ,在一个模块中this和export, module.exports的优先级关系(module.exports--->exports,this)

console.log(this,exports,module.exports)

this.val = 'this';
exports.val = 'exports';
module.exports = {val:'module.exports'} ;

console.log(this,exports,module.exports)

f10a384e395046e5a3268e4068799b7d.png

可以看到最开始module.exports,exports, this都是一个空对象(可以去改属性,但是不能去修改这个对象,否则导入会产生问题),因为this和exports是指向的同一个对象,所以,exports的赋值覆盖了this

console.log(this,exports,module.exports)

exports.val = 'exports';
this.val = 'this';
module.exports = {val:'module.exports'} ;

console.log(this,exports,module.exports)

f0cc8956429c47c794f7cb8a7761f0c3.png

颠倒一下顺序很容易就能看出来,而module.exports不一样,如果有单独导出值,那么它会以导出的值为准,若没有,则会以this和exports的值为准

大致就是:如果module.exports有值,则返回module.exports,否则,会将this,export的值赋值给module.exports,再返回module.exports;

 

下面测试一下导入的结果

index.js

exports.val = 'exports';
this.val = 'this';
module.exports = {val:'module.exports'} ;

b.js 


const index = require('./index')

console.log(index);

dc854b695bd0418dabec18f90bd2a818.png

 

 index.js


exports.val = 'exports';
this.val = 'this';
// module.exports = {val:'module.exports'} ;

b.js  


const index = require('./index')

console.log(index);

9e7f779d589d4031997b7852fadcbb42.png 

可以看到,最终就是区分有没有给module.exports赋值,有的话以module.exports为准,没有的话,把this,exports(this和exports是同一个对象,this === export)的值赋给module.exports,再以module.exports为准

 

 

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

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

相关文章

使用“天聚数行”藏头诗生成API:轻松创作个性化诗词

在日常生活中,有时我们需要一些创意的方式来表达情感或增加趣味性。“天聚数行”提供的藏头诗生成API就是一个很好的工具,可以帮助我们轻松创作个性化的诗词。以下是关于如何使用这一API的详细介绍。 API概述 “天聚数行”的藏头诗生成API是上海觉克信息…

别给智能猫砂盆花冤枉钱了!这三款好用智能猫砂盆哪个更好用?

节假日回老家,不方便带猫咪怎么办?而且猫咪这么能拉,猫砂盆里拉满了又怎么办?猫砂盆一满,就会变脏,变脏了小猫就会抗拒上厕所,从而在家里找其他干净的地方排泄,那我们要怎么保证不在…

AIOT边缘计算机助力智慧储能,开启能源管理新时代

智慧储能能源管理正成为实现可持续发展和高效能源利用的关键。而 AIOT(人工智能物联网)边缘计算机的出现,为智慧储能能源管理带来了全新的机遇和突破。 一、AIOT 边缘计算机的特点 强大的计算能力 AIOT 边缘计算机具备高性能的处理器和充足…

widows安装配置mamba_ssm环境

由于现在mamba大火,所以将mamba_ssm在windows中的环境配置进行介绍,如果你想在windows中进行开发,那么这是你最好的选择!! 安装步骤 1.anaconda下载 官网下载:https://www.anaconda.com/download 下载好…

Java笔试面试题AI答之JDBC(4)

文章目录 19. 解释JDBC的ResultSet是什么 ?20. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?JDBC编程的不足之处MyBatis如何解决这些问题 21. 简述JDBC 能否处理 Blob 和 Clob ?1. JDBC对Blob和Clob的支持2. 处理Blob和C…

【LeetCode】09.回文数

题目要求 解题思路 主要是提防越界问题 代码实现 class Solution { public:bool isPalindrome(int x) {//处理边界if(x<0) return false;long tempx,ret0;while(temp){retret*10temp%10;temp/10;}return xret;} };

Java并发编程实战 01 | 进程和线程

最早的计算机就像一个新手服务员&#xff0c;只有在接收到每一条指令时才会开始执行。当用户输入指令时&#xff0c;计算机会执行这条指令&#xff0c;然后等待下一条指令。如果用户在思考或者犹豫时&#xff0c;计算机就会乖乖地等待&#xff0c;效率实在是有点低&#xff0c;…

Swagger UI 无法发送 Cookie

文章目录 背景分析解决参考背景 项目中使用 Cookie 传递用户唯一标识,并在 Swagger 中添加 Cookie 作为全局请求参数。 尽管后端配置了 Cookie 请求参数,但在 Swagger UI 中使用 Try it out 发起请求时,发现请求中并没有 Cookie 传递过去。😭 首先,能看到 Curl 上已经有…

高级编程语言翻译例题

编译器的流程 源程序—词法分析—语法分析—语义分析—中间代码生成—代码优化—目标代码生成—目标程序 选项A&#xff1a;先进性词法分析&#xff0c;接着进行语法分析&#xff0c;最后进行语义分析 选项B&#xff1a;语法分析阶段只能发现程序上的语法错误&#xff0c;其…

软考高项通过率最高?!证书价值大吗?什么时候能报考?

近期有省份公布了2024年上半年软考合格人员名单&#xff0c;不少人说软考高项通过率最高&#xff0c;导致一些人十分想报名软考高项&#xff0c;从而拿证书。 那么&#xff0c;软考高项证书价值大吗&#xff1f;什么时候能报考&#xff1f; 1、通过率分析 在浙江公布的2024年…

YOLOv9改进策略【注意力机制篇】| GAM全局注意力机制: 保留信息以增强通道与空间的相互作用

一、本文介绍 本文记录的是基于GAM注意力模块的YOLOv9目标检测改进方法研究。GAM注意力模块通过3D排列和重新设计的子模块&#xff0c;能够在通道和空间方面保留信息&#xff0c;避免了先前方法中由于信息减少和维度分离而导致的全局空间-通道交互丢失的问题。本文利用GAM改进…

UML的图及其他图补充

一、UML图 1.类图 ‌类图‌是统一建模语言&#xff08;UML&#xff09;中的一种静态结构图&#xff0c;主要用于描述软件系统的静态结构。它显示了模型中的类、类的内部结构以及它们与其他类的关系。类图是面向对象建模的主要组成部分&#xff0c;用于对系统的词汇进行建模、对…

android开发---Kotlin语言基础语法

目录 数据打印 变量 函数 程序逻辑控制 if when 循环 数据打印 IDE采用的androidStudio 可自行官网下载 https://developer.android.google.cn/studio/archive?hlzh-cn 新建项目 添加一个main方法&#xff0c;main()函数的左边出现了一个运行标志的小箭头。现在我们只…

LLaMA-Factory仓基础功能架构及NPU/GPU环境实战演练

LLaMA-Factory 基础篇 LLaMA-Factory简介 LLaMA-Factory是一个开源的大规模语言模型微调框架&#xff0c;设计用于简化大模型的训练过程。它提供了一个统一的平台&#xff0c;支持多种大模型的微调&#xff0c;包括LLaMA、BLOOM、Mistral等&#xff0c;旨在帮助用户快速适应和…

数据脱敏处理

有关于数据脱敏处理&#xff0c;小编也是在文章上面看到的&#xff0c;感觉很有意思&#xff0c;那么&#xff0c;便深入研究了一下&#xff0c;首先我们先来看一下数据脱敏之后的结果吧&#xff1f; 用结果说话更能深入人心&#xff01;&#xff01; 下面是数据库中的字段&a…

fantastic-admin前端+django后端,初始化全流程记录

fantastic-admin前端是我目前看到最完善的前端框架&#xff0c;只需要简单的设置就可以快速开始项目。 但是我本人的能力有限&#xff0c;对前端知识一知半解&#xff0c;之前废了九牛二虎之力才跑通了前后端流程&#xff0c;由于新的项目需要&#xff0c;有了开发新后台的想法…

了解PD快充协议和QC快充协议

PD快充协议的实现依赖充电器与设备之间的通信协议&#xff0c;这种通信协议确保了充电器能够提供设备所需要的特定电压和电流。在快充技术中快充协议起到关键角色。 现在市面上最常见的快充协议有PD、QC、华为FCP/SCP、三星AFC协议 、VOOC闪充。PD和QC 协议属于公用协议 。华…

C/C++经典排序问题,sort函数使用

目录 1. 前言 2. 正文 2.1 问题 2.2 解决办法 2.2.1 思路 2.2.2 代码实现 2.2.3 测试结果 3. 备注 1. 前言 大家在学习C语言的时候&#xff0c;是不是经常被排序算法折磨的很难那首&#xff0c;其实都是但是在C中有专门的&#xff0c;排序函数&#xff0c;而且支持自定…

vue系统获取授权平台授权码实现单点登录、注销功能

公司平台需要对接别的平台 实现单点登录 注销。简而言之&#xff0c;不需要在自己公司系统登录 统一在别的平台登录后获取到登录凭证&#xff08;授权码&#xff09; 在本公司系统实现免密登录的功能。 流程&#xff1a; 跳转授权页面和保存授权码的代码&#xff1a; hrefLog…

模型融合创新性好强!最新成果直接登顶SOTA,分分钟拿下顶会

Transformer作者创业新成果火了&#xff01;他们提出了一个70亿参数的日语数学大模型&#xff0c;直接打败700亿参数的Llama-2取得SOTA&#xff01;更牛的是&#xff0c;得出这样的模型无需任何梯度训练&#xff0c;所需计算资源大大减少。 这种炸裂的成果得益于模型融合&…