1.概述:

Node应用由模块组成,采用CommonJS模块规范。

根据这个规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

如果想在多个文件分享变量,必须定义为global对象的属性。可以被所有文件读取。这样写法是不推荐的。

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX; 上面代码通过module.exports输出变量x和函数addX。 Node内部提供一个Module构建函数。所有模块都是Module的实例。
每个模块内部,都有一个module对象,代表当前模块。它有以下属性。
module.id 模块的识别符,通常是带有绝对路径的模块文件名。
module.filename 模块的文件名,带有绝对路径。
module.loaded 返回一个布尔值,表示模块是否已经完成加载。
module.parent 返回一个对象,表示调用该模块的模块。
module.children 返回一个数组,表示该模块要用到的其他模块。
module.exports 表示模块对外输出的值。

2.module.exports 和 exports

module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取 module.exports变量。

exports变量:

为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令。

var exports = module.exports;
exports.hello = function() {
return 'hello';
}; module.exports = 'Hello world';

  

上面代码中,hello函数是无法对外输出的,因为module.exports被重新赋值了。

这意味着,如果一个模块的对外接口,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。

3.require命令

require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。

如果模块输出的是一个函数,那就不能定义在exports对象上面,而要定义在module.exports变量上面
module.exports = function () {
console.log("hello world")
} require('./example2.js')() 上面代码中,require命令调用自身,等于是执行module.exports,因此会输出 hello world。

4.加载规则

require命令用于加载文件,后缀名默认为.js

var foo = require('foo'); 等同于 var foo = require('foo.js');

根据参数的不同格式,require命令去不同路径寻找模块文件。
(1)如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,require('/home/marco/foo.js')将加载/home/marco/foo.js。 (2)如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,require('./circle')将加载当前脚本同一目录的circle.js (3)如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。 (4)如果参数字符串不以“./“或”/“开头,而且是一个路径,比如require('example-module/path/to/file'),则将先找到example-module的位置,然后再以它为参数,找到后续路径。 (5)如果指定的模块文件没有发现,Node会尝试为文件名添加.js、.json、.node后,再去搜索。.js件会以文本格式的JavaScript脚本文件解析,.json文件会以JSON格式的文本文件解析,.node文件会以编译后的二进制文件解析。 (6)如果想得到require命令加载的确切文件名,使用require.resolve()方法。

5.目录的加载规则

通常,我们会把相关的文件会放在一个目录里面,便于组织。这时,最好为该目录设置一个入口文件,让require方法可以通过这个入口文件,加载整个目录。
在目录中放置一个package.json文件,并且将入口文件写入main字段。下面是一个例子。
// package.json
{ "name" : "some-library",
"main" : "./lib/some-library.js"
}
require发现参数字符串指向一个目录以后,会自动查看该目录的package.json文件,然后加载main字段指定的入口文件。如果package.json文件没有main字段,或者根本就没有package.json文件,则会加载该目录下的index.js文件或index.node文件。 第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的module.exports属性。 如果想要多次执行某个模块,可以让该模块输出一个函数,然后每次require这个模块的时候,重新执行一下输出的函数。 Node执行一个脚本时,会先查看环境变量NODE_PATH。它是一组以冒号分隔的绝对路径。在其他位置找不到指定模块时,Node会去这些路径查找。
如果遇到复杂的相对路径,比如下面这样。
var myModule = require('../../../../lib/myModule');
有两种解决方法:
一是将该文件加入node_modules目录,二是修改NODE_PATH环境变量,package.json文件可以采用下面的写法。

  

  

 

最新文章

  1. js 逻辑或
  2. spring开发的总结
  3. JSP九大内置对象的作用和用法总结?
  4. POJ3903:Stock Exchange(LIS)
  5. thinkphp 的create()非法数据解决办法
  6. Web API 入门系列- 从一个示例开始
  7. 微软Hololens学院教程- Holograms 100: Getting Started with Unity【微软教程已经更新,本文是老版本】
  8. C#- 泛型去除重复项
  9. Cidr计算
  10. text bss data的区别
  11. 【Java IO流】File类的使用
  12. LinkStack
  13. 解决EJB本地调用“java.lang.ClassCastException: $Proxy96 cannot be cast to com.tgb.ejb.UserManager”异常
  14. Linux Shell 命令--tr
  15. PHP:第一章——PHP中的变量002
  16. springboot创建错误
  17. spring security笔记
  18. Qt5_qtconfig
  19. linux命令总结之date命令
  20. Eclipse debug模式 总是进入processWorkerExit

热门文章

  1. tcpdump用法说明
  2. Activity工作流框架入门(二)API使用DEMO
  3. HTTPS详解二:SSL / TLS 工作原理和详细握手过程
  4. Linux防火墙之iptables扩展处理动作
  5. web语义化这个坑
  6. windows7_下Eclipse中部署tomcat7.0进行JSP+servlet开发
  7. 【Java并发工具类】Semaphore
  8. windows系统快速安装pytorch的详细教程
  9. UVA5913 Dictionary Sizes(字典树)(转载)
  10. C++用rand()和srand()生成随机数