CommonJS浅析

规范地址 http://www.commonjs.org/
nodejs modules文档地址 http://nodejs.cn/api/modules….

核心逻辑

在执行模块代码之前,nodejs会使用一个闭包(The module wrapper)封装起来,这就是它每一个文件都是一个独立的域的原因。但如果值没有用var声明的变量,会直接提升到全局上去,在其他文件也可以直接使用。

nodejs会通过下面一个闭包把文件给包起来

(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});

我们可以使用

console.log(JSON.stringify(arguments))
可以看到当前js文件封装之后的参数
例:
aa.js
console.log(JSON.stringify(arguments))
//  {"0":{},"2":{"id":".","exports":{},"parent":null,"filename":"D:\\code\\js\\aa.js","loaded":false,"children":[],"paths":["D:\\code\\js\\node_modules","D:\\code\\node_modules","D:\\node_modules"]},"3":"D:\\code\\js\\aa.js","4":"D:\\code\\js"}‘

可以看到这里返回的对象对应着exports, require, module, __filename, __dirname

exports

在整个域里,会有两个exports,一个模块封装器里的首个参数,一个是module类里的。
两个exports引用了同一块堆内存,require引用时实际上拿的是module类里的

require

用于引入模块、 JSON、或本地文件。 可以从 node_modules 引入模块。 可以使用相对路径(例如 ./、 ./foo、 ./bar/baz、 ../foo)引入本地模块或 JSON 文件,路径会根据 __dirname 定义的目录名或当前工作目录进行处理。

上面是官网对require的定义,require的一些属性使用在官网也有定义

module

在每个模块中, module 的自由变量是对表示当前模块的对象的引用。 为方便起见,还可以通过全局模块的 exports 访问 module.exports。 module 实际上不是全局的,而是每个模块本地的。

__filename

当前模块的文件名。 这是当前的模块文件的绝对路径(符号链接会被解析)。

__dirname

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

特殊使用

循环引用

当循环调用 require() 时,一个模块可能在未完成执行时被返回。

例如以下情况:

a.js:

console.log('a 开始');
exports.done = false;
const b = require('./b.js');
console.log('在 a 中,b.done = %j', b.done);
exports.done = true;
console.log('a 结束');
b.js:

console.log('b 开始');
exports.done = false;
const a = require('./a.js');
console.log('在 b 中,a.done = %j', a.done);
exports.done = true;
console.log('b 结束');
main.js:

console.log('main 开始');
const a = require('./a.js');
const b = require('./b.js');
console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);

当 main.js 加载 a.js 时, a.js 又加载 b.js。 此时, b.js 会尝试去加载 a.js。 为了防止无限的循环,会返回一个 a.js 的 exports 对象的 未完成的副本 给 b.js 模块。 然后 b.js 完成加载,并将 exports 对象提供给 a.js 模块。

当 main.js 加载这两个模块时,它们都已经完成加载。 因此,该程序的输出会是:

$ node main.js
main 开始
a 开始
b 开始
在 b 中,a.done = false
b 结束
在 a 中,b.done = true
a 结束
在 main 中,a.done=true,b.done=true


    原文作者:fuqihan
    原文地址: https://segmentfault.com/a/1190000019506117
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞