Node.js的模块机制

为了让文件可以相互调用,Node.js提供了一个简单的模块系统,采用CommonJS模块规范。
模块是Node.js应用程序的基本组成部分,文件和模块是一一对应的,每个文件就是一个模块。

CommonJS规范

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

// sum.js
let sum=0; // sum是sum.js私有变量,其他文件(模块)不可见
for (let i = 1; i <=100 ; i++) {
    sum+=i;
}
console.log(sum);

每个模块内部,module代表当前模块,这个变量是一个对象,它的exports属性(module.exports)是对外的接口。加载某个模块,其实是加载该模块的exports属性。

// sum.js
let sum=0; // sum是sum.js私有变量,其他文件(模块)不可见
for (let i = 1; i <=100 ; i++) {
    sum+=i;
}
console.log(sum);
module.exports.sum=sum; // 输出变量sum

特点

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

Module对象

Node.js内部提供Module构建函数,所有的模块都是Module的实例。

function Module(id,parent)

在Node.js执行一个文件时,会给这个文件生成一个module对象和exports变量。module对象代表当前模块,另外,module对象有一个exports属性,module.exports和exports都指向同一块内存区域。

module.exports = exports = {};

Node.js的模块机制_第1张图片
image.png
module.exports属性

module.exports属性表示当前模块对外输出的接口。其他文件加载该模块,实际上就是读取的module.exports变量。

module.exports.sum=100;

module.exports.area = function (r) {
    return Math.PI * r * r;
}
exports变量

Node.js为每个模块提供了一个exports变量,指向module.exports。等同于在模块的头部有一个这样的命令:var exports = module.exports;

exports.sum =100;

exports.area = function (r) {
    return Math.PI * r * r;
}

require命令

require命令用于加载模块文件,如果没有会报错。

加载规则

  • http、fs、path、url,内置模块,引入无路径
  • ./mod或../mod,相对路径的文件模块
  • /pathtomodule/mod,绝对路径文件
  • mod,非原生模块的文件模块

注:

  1. requrie命令用于加载文件,后缀名默认为.js。require('./test');// 等同于require('./test.js');
  2. 如果指定的模块文件没有发现,Node.js会尝试为文件名添加.js、.json、.node后再去搜索。

模块分类

Node.js中模块可以通过文件路径或名字获取模块的引用。模块的引用会映射到一个js文件的路径,除非它是一个内置模块。Node.js的内置模块公开了一些常用的API给开发者,并且它们在Node.js进程开始的时候就预记载了。

内置模块

Node.js的内置模块被编译成二进制形式,引用时直接使用名字而非文件路径。当第三方模块和内置模块同名时,内置模块将覆盖第三方同名模块。

let http = require('http');
第三方模块(node_modules中,npm安装)

如果模块名不是路径,也不是内置模块,Node.js将试图去当前目录的node_modules文件夹中去搜索,如果没有找到,就从父目录的node_modules中去搜索,一直到根目录。

npm命令可以方便的安装、卸载、更新node_modules目录。

let express = require('express');
文件模块

用户自己编写的模块,文件模块是按需加载的。

// 绝对路径
let test = require('/Users/hhh/Desktop/node/test.js')
// 相对路径
let test = require('./test.js')
let test = require('./test') // 等价于let test = require('./test.js');
文件目录模块
let test = require('./folder') // 等价于let test = require('./folder/index.js'); 如果不存在,则加载失败

模块加载优先级

Node.js的模块机制_第2张图片
nodejs-require.jpg

从文件模块缓存中加载

尽管原生模块与文件模块的优先级不同,但是会优先从文件模块的缓存中加载已经存在的模块。

从原生模块中加载

原生模块的优先级仅次于文件模块缓存的优先级。require方法在解析文件名之后,优先检查模块是否在原生模块列表中。原生模块也有缓存区,优先从缓存区加载,如果缓冲区没有被加载过,则调用原生模块的加载方式进行加载和执行。

从文件中加载

当文件缓存模块中不存在,而且也不是原生模块的时候,Node.js会解析require方法传入参数,并从文件系统中加载实际文件。

参考

  • http://www.runoob.com/nodejs/nodejs-module-system.html
  • https://blog.csdn.net/w_q_1025/article/details/54896346
  • http://javascript.ruanyifeng.com/nodejs/module.html
  • https://www.cnblogs.com/littlebirdlbw/p/5670633.html

你可能感兴趣的:(Node.js的模块机制)