模块的概念
Node 应用由模块组成,采用 CommonJS 模块规范。
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
模块的特点
- 所有代码都运行在模块作用域,不会污染全局作用域。
- 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
- 模块加载的顺序,按照其在代码中出现的顺序。
module.id 模块的识别符,通常是带有绝对路径的模块文件名。
module.filename 模块的文件名,带有绝对路径。
module.loaded 返回一个布尔值,表示模块是否已经完成加载。
module.parent 返回一个对象,表示调用该模块的模块。
module.children 返回一个数组,表示该模块要用到的其他模块。
module.exports 表示模块对外输出的值。
模块加载
加载方式
const Square = require('./square.js');
加载路径
require(X) from module at path Y
If X is a core module,
a. return the core module
b. STOP
If X begins with '/'
a. set Y to be the filesystem root
If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
LOAD_NODE_MODULES(X, dirname(Y))
THROW "not found"
入口文件
将程序和库组织到自包含目录中很方便,然后为该库提供单个入口点。有三种方法可以将文件夹require()作为参数传递给它。
{"name" : "some-library",
"main" : "./lib/some-library.js" }
- 第一种是package.json在文件夹的根目录中创建一个文件,该文件指定一个main模块。示例package.json文件可能如上图所示:
- 如果传递给的模块标识符require()不是 核心模块,并且不以’/’,’../’或 开头’./’,则Node.js从当前模块的父目录开始,然后添加/node_modules,并尝试从该位置加载模块。节点不会附加node_modules到已经结束的路径node_modules。
- 如果NODE_PATH环境变量设置为冒号分隔的绝对路径列表,则Node.js将搜索这些路径以查找模块(如果在其他位置找不到它们)。
核心模块
Node.js有几个模块编译成二进制文件。
这些核心模块在Node.js的源中定义,位于 lib/文件夹中。
如果传递标识符,则始终优先加载核心模块require()。例如require(‘http’),即使存在该名称的文件,也将始终返回内置的HTTP模块。
模块包装
在执行模块代码之前,Node.js将使用如下所示的函数包装器来包装它:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
通过这样做,Node.js实现了以下几点:
1. 它使顶层变量(与定义var,const或let)作用域到模块,而不是全局对象。
2. 它有助于提供一些实际上特定于模块的全局变量,例如:
在module和exports对象的实现者可以用它来从模块输出值。
3. 便利变量__filename和__dirname,包含模块的绝对文件名和目录路径。