规范地址 http://www.commonjs.org/
nodejs modules文档地址 http://nodejs.cn/api/modules....html
在执行模块代码以前,nodejs会使用一个闭包(The module wrapper)封装起来,这就是它每个文件都是一个独立的域的缘由。但若是值没有用var声明的变量,会直接提高到全局上去,在其余文件也能够直接使用。node
nodejs会经过下面一个闭包把文件给包起来api
(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, __dirnameapp
在整个域里,会有两个exports,一个模块封装器里的首个参数,一个是module类里的。
两个exports引用了同一块堆内存,require引用时实际上拿的是module类里的ui
用于引入模块、 JSON、或本地文件。 能够从 node_modules 引入模块。 可使用相对路径(例如 ./、 ./foo、 ./bar/baz、 ../foo)引入本地模块或 JSON 文件,路径会根据 __dirname 定义的目录名或当前工做目录进行处理。code
上面是官网对require的定义,require的一些属性使用在官网也有定义htm
在每一个模块中, module 的自由变量是对表示当前模块的对象的引用。 为方便起见,还能够经过全局模块的 exports 访问 module.exports。 module 实际上不是全局的,而是每一个模块本地的。对象
当前模块的文件名。 这是当前的模块文件的绝对路径(符号连接会被解析)。内存
当前模块的目录名。 与 __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