NodeJs一个模块中的JS代码仅在模块第一次被使用时执行一次,并在执行过程中初始化模块的导出对象。之后,缓存起来的导出对象被重复利用。并不因为被 "require" 了两次而初始化两次。
模块路径解析规则
1.内置模块
如果传递给require
函数的是NodeJS内置模块名称,不做路径解析,直接返回内部模块的导出对象,例如require('fs')
。
nodejs内置模块:path模块、until模块、fs模块、events模块、http模块等
2.node_modules目录
NodeJS定义了一个特殊的node_modules
目录用于存放模块。例如某个模块的绝对路径是/home/user/hello.js
,在该模块中使用require('foo/bar')
方式加载模块时,则NodeJS依次尝试使用以下路径。
/home/user/node_modules/foo/bar
/home/node_modules/foo/bar
/node_modules/foo/bar
即,一级一级往上找
3.NODE_PATH环境变量
与PATH环境变量类似,NodeJS允许通过NODE_PATH环境变量来指定额外的模块搜索路径。NODE_PATH环境变量中包含一到多个目录路径,路径之间在Linux下使用:
分隔,在Windows下使用;
分隔。例如定义了以下NODE_PATH环境变量:
NODE_PATH=E:/nodepath;E:/
当使用require('nodepathJs')
的方式加载模块时,则NodeJS依次尝试以下路径。
E:/nodepath/nodepathJs
E:/nodepathJs
当然,如果你前面设置NODE_PATH时,两个路径顺序调换了下,那么此时的查询顺序也就要反过来。
具体的另起一章,不在这边细讲。
当模块的文件名是index.js
,加载模块时可以使用模块所在目录的路径代替模块文件路径。
如果想自定义入口模块的文件名和存放位置,就需要在包目录下包含一个package.json
文件,并在其中指定入口模块的路径。上例中的cat
模块可以重构如下。
- /home/user/lib/
- cat/
+ doc/
- lib/
head.js
body.js
main.js
+ tests/
package.json
其中package.json
内容如下。
{
"name": "cat",
"main": "./lib/main.js"
}
如此一来,就同样可以使用require('/home/user/lib/cat')
的方式加载模块。NodeJS会根据包目录下的package.json
找到入口模块所在位置。
4.工程目录
工程目录一般如下结构
- /home/user/workspace/ # 工程目录
- bin/ # 存放命令行相关代码
node-echo
+ doc/ # 存放文档
- lib/ # 存放API相关代码
echo.js
- node_modules/ # 存放三方包
+ argv/
+ tests/ # 存放测试用例
package.json # 元数据文件
README.md # 说明文件
5.process.argv获取命令行参数
process
是一个全局变量,可通过process.argv
获得命令行参数。由于argv[0]
固定等于NodeJS执行程序的绝对路径,argv[1]
固定等于主模块的绝对路径,因此第一个命令行参数从argv[2]
这个位置开始
6.fs模块
fs.readFileSync,fs.writeFileSync用来读写数据,一般用于小文件拷贝。fs.createReadStream,fs.createWriteStream也用来读写数据,但可以用于大文件拷贝。
7.Buffer
Buffer
与字符串有一个重要区别。字符串是只读的,并且对字符串的任何修改得到的都是一个新字符串,原字符串保持不变。至于Buffer
,更像是可以做指针操作的C语言数组。因此,如果想要拷贝一份Buffer
,得首先创建一个新的Buffer
,并通过.copy
方法把原Buffer
中的数据复制过去。