规范地址http://www.commonjs.org/nodejsmodules文档地址http://nodejs.cn/api/modules....核心逻辑在执行模块代码之前,nodejs会使用一个封闭的包(模块包装器),这就是为什么它的每个文件都是一个独立的域。但如果该值不是用var声明的变量,则直接提升为全局,可以直接在其他文件中使用。nodejs会通过下面的闭包来包装文件(function(exports,require,module,__filename,__dirname){//模块的代码其实在这里});我们可以使用console.log(JSON.stringify(arguments))可以看到当前js文件封装后的参数例子:aa.jsconsole.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,__dirnameexports在整个域中,会有两个exports,第一个参数在模块包装器中,一个在模块类中。两个export引用的是同一个堆内存,require引用其实是使用模块类中的require来导入模块、JSON或者本地文件。模块可以从node_modules导入。可以使用相对路径(如./、./foo、./bar/baz、../foo)导入本地模块或JSON文件,路径会根据__dirname定义的目录名或当前目录名进行处理工作目录。以上是官网对require的定义。官网使用了require的一些属性,在各个模块中定义了module。模块的自由变量是对表示当前模块的对象的引用。为方便起见,也可以通过全局模块的导出访问module.exports。module实际上不是全局的,而是每个模块的本地。__filename当前模块的文件名。这是当前模块文件的绝对路径(已解析符号链接)。__dirname当前模块的目录名。与__filename的path.dirname()相同。循环引用的特殊用途当对require()进行循环调用时,模块可能会在未完成执行的情况下返回。例如下面的情况:a.js:console.log('astarted');exports.done=false;constb=require('./b.js');console.log('ina,b.done=%j',b.done);exports.done=true;console.log('aends');b.js:console.log('bstarts');exports.done=false;consta=require('./a.js');console.log('inb,a.done=%j',a.done);exports.done=true;控制台。日志('b完成');主要。js:console.log('mainstarts');consta=require('./a.js');constb=require('./b.js');console.log('Inmain,a.done=%j,b.done=%j',a.done,b.done);当main.js加载a.js时,a.js加载b.js。此时b.js会尝试加载a.js。为防止无限循环,将a.js导出对象的未完成副本返回给b.js模块。然后b.js完成加载并将exports对象提供给a.js模块。当main.js加载这两个模块时,它们都已经加载。所以这个程序的输出是:$nodemain.jsmainstartastartbstartinb,a.done=falsebendina,b.done=trueaendinmain,a.done=true,b.done=真
