文件即模块
类似于其他语言中"包(package)"或"名称空间(namespace)"等概念,Node.js使用"模块(Module)"来规划不同的功能对象。
Node.js中每个被加载的文件对应一个模块对象。
一个文件/模块被第一次加载后,会在内存中保存对应的缓存对象;对一个模块多次重复引入,会使用该缓存对象,从而避免了重复加载导致创建出多个完全相同的模块对象。
主模块与子模块
与C等其他语言类似,Node.js启动时运行的第一个模块成为"主模块"——main module。
那么如何获取住模块对象呢?
//可以使用下述方法获取住模块对象
console.log(process.mainModule);
console.log(require.main);
除主模块的其他模块都称为"子模块"。
每个子模块都可以导出(exports)一些数据或其他方法供其他模块使用。
要是有其他模块功能,当前模块需要引入(require)指定的模块。
//判断当前模块是否是"主模块"
console.log(module===process.mainModule);
每个模块都可以使用一个变量module,它指向当前模块自己。可以用module是否等于当前程序主模块来判断当前模块是否是主模块。
创建模块
/**子模块:child.js***/
const PI=3.14;
//导出方法供其他模块使用
exports.size=function(r){
return PI*r*r;
}
//导出方法供其他模块使用
exprots.perimeter=function(r){
return 2*PI*r;
}
/**主模块:app.js**/
const circle=require('./child.js')//引入子模块
console.log(cricle.size(3)); //调用子模块提供的方法
console.log(circle.perimeter(3));
模块的封装
Node.js中的每个.js文件都自成一个模块,有自己专属的成员属性和方法——"模块作用域"变量。模块文件中声明的变量和函数也都属于"模块作用域"。根本原因在于,Node.js在编译文件时会对其首尾进行如下包装:
(function(exports,require,module,__filename,__dirname){
module.exports={};
exports=module.exports;
//模块文件中原有的全部内容
return module.exports
});
模块作用域变量
提示:声明在文件模块文件中的"全局变量"不再是真正的全局变量,即不是global对象的成员了;而是当前模块内部的局部变量。
成员名 | 说明 |
---|---|
__dirname : String | 当前模块文件所在的目录名 |
__filename : String | 当前模块文件的文件名 |
module : Object | 指向当前模块的引用 |
module.exports : Object | 当前模块中待导出的供其他模块使用的对象 |
exports : Object | 指向module.exports对象的引用 |
require : Function | 引入其他模块,使其他模块的module.exports对象 |
modeule.exprots和exports
一个模块可以导出一个供其他模块使用的对象,这个对象就是module.exports对象。起始时,他是一个{ }对象。
exports对象作为module.exports对象的引用,可u作为module.exports的简写形式使用。
注意:其他模块可以引入的是module.exports对象,而不是exports对象!所以一下两种情形的结果是不同的:
exports.add=function(){}
//等同于
module.exports.add=fucntion(){}
exports=function(){}//无效
//不等同于
module.exports=function(){}//有效
exports=function(){}只是修改了exports的指向,此导出不会产生任何效果。
模块的分类
核心模块
被编译进二进制文件,可以被解释器直接使用,加载速度最快;
模块名 | 说明 |
---|---|
global | 全局对象模块 |
console | 控制台模块 |
util | 提供常用函数的集合,用于弥补核心JS的功能过于精简的不足 |
events | 实现了Node.js的事件驱动型的异步调用 |
fs | 文件系统I/O操作模块 |
http | 提供基于HTTP协议的请求和响应 |
net | 提供Socket的网络连接 |
dns | DNS解析服务模块 |
crypto | 加密和解密模块 |
文件模块
没有后缀名的文件模块,被作为Javascript文本加载;
.js后缀的文件模块,被作为Javascript文本加载;
.json后缀的文件模块,被最为JSON字符串加载;
.node后缀的文件模块,被作为C/C++二进制插件加载;
目录模块
包含package.json文件的目录;
包含index.js文件的目录;
包含index.json文件的目录;
包含index.ndoe的文件目录;
require()
require( )函数用于引入另一个模块,其可用的参数有如下形式:
核心模块名
const http=require("http");
相对或绝对路径开头的模块名
const c1=require("./calc"); //可能是文件模块或者是目录
const c2=require("../calc"); //可能是文件模块或者是目录
const c3=require("/calc"); //可能是文件模块或者是目录
不以路径开头的非核心模块名
const mysql =require('mysql');//可能是文件模块或者是目录
非核心模块的查找路径
对于每个被加载的文件模块,创建这个模块对象的时候,module对象便有一个paths属性,用于指定查找不以"./"或"../"或"/"开头的模块名时所用到的路径。其值例如:
['c:\\mynode\\project1\\lib\\node_modules',
'c:\\mynode\\project1\\node_modules',
'c:\\mynode\\node_modules',
'c:\\node_modules']
模块查找的顺序
(1)文件/目录模块的缓存
(2)原生模块的缓存
(3)原生模块
(4)文件/目录模块