Node.js模块系统(Node.js自学第四天)

807 阅读4分钟

文件即模块

类似于其他语言中"包(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)文件/目录模块

未命名文件 (1).png