当前位置:网站首页>一道代码题看 CommonJS 模块化规范
一道代码题看 CommonJS 模块化规范
2022-07-23 09:27:00 【火星飞鸟】
CommonJS
在node.js中,使用 CommonJS 作为其模块化规范。
根据 CommonJS 模块化规范,一个单独的JS文件就是一个模块,每个模块是一个单独的作用域,在模块内部定义的变量,无法在其他模块中所读取。若想要在模块间进行通信,需使用模块的导出与导入语法:
- 模块通过变量
exports向外暴露API,注意,exports只能是一个对象,该对象的属性即为向外暴露的API。 - 在另一个模块中,通过全局函数
require引入其他模块导出的exports对象。
基本语法
例如,a.js文件中导出对象exports,其中包含了name、add属性,分别是文件中定义的常量。
const name = 'Jack';
const add = (a, b) => a + b;
module.exports = {
name,
add
};
在文件b.js中,通过全局函数require引入该导出的对象exports。
const api = require('./a');
console.log(api);
// { name: 'Jack', add: [Function: add] }
注意,api这个可以随意取的。通常,也可以通过解构赋值的形式,按需进行导入:
const {
name } = require('./a');
console.log(name);
// Jack
多次导入
接上述例子,若在b.js文件中,多次导入a模块,会怎么样呢?两次导入的是同一个对象吗?
const api1 = require('./a');
const api2 = require('./a');
console.log(api1 === api2);
// true
如上述代码所示,b.js中两次引入a模块,并判断两个导入的变量是否为相等。结果输出true,说明若多次引用,实际上导入的模块是同一个对象。
实际上,在第一次导入中,会执行要导入的文件,并在内存中缓存一个对象,其中exports就是要导入的对象。再次导入相同模块时,并不会再执行了,会直接从内存中取这个exports对象。
{
id: '...', // 模块名
exports: {
... }, // 模块输出的接口
loaded: true, // 模块的脚本是否执行完毕
...
}
是否支持更改
导入模块,实际上就是执行一遍要导入的模块,然后将其输出的exports对象,作为require函数的返回值。实际上就是普通的赋值语句,若使用var、let进行声明,当然支持更改。
let api1 = require('./a');
api1 = {
};
console.log(api1);
// {}
循环引用
若出现某模块被循环加载,只输出已经执行的部分,未执行的不会输出。
若在a.js中引入b.js,在b.js中引入a.js,形成循环引用,是否会报错呢?若不报错,运行的结果是怎么样的?
还是以代码举例比较清晰。如下代码所示,a模块引入b模块,b模块引入a模块。
// a.js
const b = require('./b');
console.log('b', b);
const name = 'Jack';
const age = 18;
module.exports = {
name,
age
};
// b.js
const a = require('./a');
console.log('a', a);
const id = '001';
module.exports = {
id
};
运行node a.js,控制台输出如下:
a {
}
b {
id: '001' }
没有报错,正常运行。这是因为前面提到的原因:若出现某模块被循环加载,只输出已经执行的部分,未执行的不会输出。
简单分析一下:
- 运行
node a.js。首先进入到a模块,a模块一开始就导入b模块,那么就会先执行一遍b.js,然后返回b.js导出的exports对象给a模块中的常量b。 - 执行
b.js。一开始又导入了a.js。但是a.js并未执行完毕,只会返回已执行的部分。由于a.js导出的是name、age,此时a.js只执行到第1行,所以实际上此时导入a.js,只会返回空对象,因为name、age还未执行到。所以require('./a')返回空对象,赋值给常量a,故打印出空对象。 - 接着继续执行
b.js,将剩下的代码执行完毕,正常导出了exports对象,其中包含了id属性。 - 执行完毕后,又回到了
a.js的第一行中,require('./b')返回b导出的exports对象,包含了id属性。所以,下面能正常打印出{ id: '001' }。 - 接着在
a.js中,将剩余的代码执行完毕。
思考题
有a.js、b.js、c.js三个文件,执行node a.js,控制台将会输出什么?
// a.js
const b = require('./b');
console.log(exports.x);
exports.x = 'x';
require('./c');
// b.js
const a = require('./a');
console.log(a);
a.x = 'y';
// c.js
const a = require('./a');
console.log(a.x);
答案:
{
}
y
x
以上为本人学习所得,若有不妥,欢迎批评指出!
边栏推荐
- 【FLink】FLink Hash collision on user-specified ID “opt“. Most likely cause is a non-unique ID
- 什麼是Per-Title編碼?
- Towhee weekly model
- 【软件测试】盘一盘工作中遇到的 Redis 异常测试
- How can manual testing turn to automated testing? Byte 5 years of automation experience talk about
- 【C语言】猜数字小游戏+关机小程序
- 基本51单片机点阵汉字显示程序设计
- Palindrome related topics
- win11安装系统提示virtualBox不兼容需要卸载virtual的解决办法,但是卸载列表找不到virtual的解决办法
- (heavy chain dissection) Magic Tree
猜你喜欢

mysql唯一索引无重复值报错重复

Qu'est - ce que le codage par titre?
![[download attached] several scripts commonly used in penetration testing that are worth collecting](/img/01/3b74c5ab4168059827230578753be5.png)
[download attached] several scripts commonly used in penetration testing that are worth collecting

Optimize Huawei ECs to use key login

Using JS to parse and execute XSS automatically

LeetCode-227-基本计算器||

LZ77文件压缩
![webstrom ERROR in [eslint] ESLint is not a constructor](/img/e9/b084512d6aa8c4116d7068fdc8fc05.png)
webstrom ERROR in [eslint] ESLint is not a constructor

Towhee weekly model

Aruba learning notes 05 configuration architecture WLAN configuration architecture
随机推荐
koa框架的使用
CAN总线快速了解
How can manual testing turn to automated testing? Byte 5 years of automation experience talk about
C language introduction practice (11): enter a group of positive integers and sum the numbers in reverse order
第4章 集合运算
Design and implementation of websocket universal packaging
First acquaintance and search set
452. Detonate the balloon with the minimum number of arrows
什么是Per-Title编码?
[test platform development] 23. interface assertion function - save interface assertion and edit echo
[download attached] several scripts commonly used in penetration testing that are worth collecting
在使用 VScode 进行代码格式化后,保存发现代码又变乱了,怎么办?vs去掉格式化
21 - 二叉树的垂直遍历
webstrom ERROR in [eslint] ESLint is not a constructor
基金开户网上办理是否安全?谁给解答一下
OpenCV计算外包矩形
C language project practice: 24 point game calculator (based on knowledge points such as structure, pointer, function, array, loop, etc.)
Work notes: one time bag grabbing
Regular verification of ID number
【测试平台开发】二十、完成编辑页发送接口请求功能