天天看点

学习笔记——Node.JS之CommonJS

模块的概念

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

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

模块的特点

  1. 所有代码都运行在模块作用域,不会污染全局作用域。
  2. 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  3. 模块加载的顺序,按照其在代码中出现的顺序。

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" }
           
  1. 第一种是package.json在文件夹的根目录中创建一个文件,该文件指定一个main模块。示例package.json文件可能如上图所示:
  2. 如果传递给的模块标识符require()不是 核心模块,并且不以’/’,’../’或 开头’./’,则Node.js从当前模块的父目录开始,然后添加/node_modules,并尝试从该位置加载模块。节点不会附加node_modules到已经结束的路径node_modules。
  3. 如果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,包含模块的绝对文件名和目录路径。