Nodejs 之 Moudule统一模块

一. 简述

  1. Node.js 有一个简单的模块加载系统。 在 Node.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)
  2. 模块内的本地变量是私有的,因为模块被 Node.js 包装在一个函数中,在执行模块代码之前,Node.js 会使用一个如下的函数包装器将其包装:
    (function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
  3. 通过这样做,Node.js 实现了以下几点:
    a. 它保持了顶层的变量(用 var、const 或 let 定义)作用在模块范围内,而不是全局对象。
    b. 它有助于提供一些看似全局的但实际上是模块特定的变量,例如:实现者可以用于从模块中导出值的 module 和 exports 对象。
    c. 包含模块绝对文件名和目录路径的快捷变量 __filename 和 __dirname 。
    d. 想要获得调用 require() 时加载的确切的文件名,使用 require.resolve(‘文件名’) 函数。

二. 模块的导出

  1. 导出模块的方式有两种,一种是:
    exports.prop = value;
    module.exports = { }
  2. exports 变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋予 module.exports 的值。
  3. 它是一个快捷方式,以便module.exports.f = ...可以被更简洁地写成 exports.f = ...
  4. 注意:就像任何变量,如果一个新的值被赋值给 exports,它就不再绑定到module.exports
console.log(module.exports===exports) 
//true
exports=[1,2,3];
console.log(exports[1])
//2
console.log(module.exports===exports)
//false

三. 将文件作为模块

  1. 如果按确切的文件名没有找到模块,则 Node.js 会尝试带上 .js、.json 或 .node 拓展名再加载。.js 文件会被解析为 JavaScript 文本文件,.json 文件会被解析为 JSON 文本文件。在这里插入图片描述

  2. / 为前缀的模块是文件的绝对路径
    例如,require("/S-娜娜酱/3.27_nodejsdemo/js/04module1.js")会加载 “/S-娜娜酱/3.27_nodejsdemo/js/04module1.js” 文件。

  3. ./ 为前缀的模块是相对于调用 require() 的文件的。
    也就是说,circle.js 必须和 foo.js 在同一目录下以便于 require(’./circle’) 找到它。

  4. 当没有以 / ./../ 开头来表示文件时,这个模块必须是一个核心模块加载自 node_modules 目录

  5. 如果给定的路径不存在,则 require() 会抛出一个 code 属性为 ‘MODULE_NOT_FOUND’ 的 Error。在这里插入图片描述

四. 将目录作为模块

可以把程序和库放到一个单独的目录,然后提供一个单一的入口来指向它。 把目录递给 require() 作为一个参数。

1.在根目录下创建一个package.json文件,并指定一个 main 模块。
例子,package.json 文件类似:

{
  "main": "./lib/a.js" 
}
  1. 如果这是在./3.28_nodejsdemo目录中,则require('.')会试图加载 ./3.28_nodejsdemo/lib/a.js
    这就是 Node.js 处理package.json 文件的方式。

  2. 注意:如果 package.json中 “main” 入口指定的文件不存在,则无法解析,Node.js 会将模块视为不存在,并抛出默认错误:
    Error: Cannot find module 'some-library'
    在这里插入图片描述

  3. 如果目录里没有 package.json 文件,则 Node.js 就会试图加载目录下的 index.jsindex.node 文件。

五. 从 node_modules 目录加载

//如果文件前没有加/,,

  1. 如果传递给 require() 的模块标识符不是一个核心模块,也没有以 / ./ ../开头,则 Node.js 会从当前目录下寻找node-modules文件夹,找不到就一层一层向上级目录里找直到根目录,直到找到为止,尝试从它的node_modules 目录里加载模块。

  2. Node.js 不会附加 node_modules 到一个已经以 node_modules 结尾的路径上。

  3. 若直到根目录都找不到,则报错。

  4. 例子,如果在 ‘/home/ry/projects/foo.js’ 文件里调用了 require(‘bar.js’),则 Node.js 会按以下顺序查找:

    /home/ry/projects/node_modules/bar.js
    /home/ry/node_modules/bar.js
    /home/node_modules/bar.js
    /node_modules/bar.js

    这使得程序本地化它们的依赖,避免它们产生冲突。

  5. 通过在模块名后包含一个路径后缀,可以请求特定的文件或分布式的子模块。 例如,require(‘example-module/path/to/file’) 会把 path/to/file 解析成相对于 example-module 的位置。 后缀路径同样遵循模块的解析语法。

六. 缓存

  1. 模块在第一次加载后会被缓存。 这也意味着(类似其他缓存机制)如果每次调用require('foo') 都解析到同一文件,则返回相同的对象。
  2. 多次调用 require(‘foo’) 不会导致模块的代码被执行多次。 这是一个重要的特性。 借助它, 可以返回“部分完成”的对象,从而允许加载依赖的依赖, 即使它们会导致循环依赖.

七. 核心模块

  1. 核心模块定义在 Node.js 源代码的 lib/ 目录下。
  2. require() 总是会优先加载核心模块。
    例如,require(‘http’) 始终返回内置的 HTTP 模块,即使有同名文件。
7.1 require对象
  1. require.cache:被引入的模块将被缓存在这个对象中。从此对象中删除键值对将会导致下一次 require 重新加载被删除的模块。注意不能删除 native addons(原生插件),因为它们的重载将会导致错误。

  2. require.main:返回主模块路径。
    在这里插入图片描述

  3. require.resolve(request):使用内部的 require() 机制查询模块的位置, 此操作只返回解析后的文件名,不会加载该模块。
    request 需要解析的模块路径

  4. require.resolve.paths(request):返回一个数组,其中包含解析 request 过程中被查询的路径。 如果 request 字符串指向核心模块(例如 http 或 fs),则返回 null。
    在这里插入图片描述

7.2 module 对象
  1. 在每个模块中,module 的自由变量是一个指向表示当前模块的对象的引用。 为了方便,module.exports也可以通过全局模块的 exports对象访问。 module 实际上不是全局的,而是每个模块本地的。
  2. module.children:被该模块引用的模块对象。
  3. module.filename:模块的完全解析后的文件名。
  4. module.id:模块的标识符。 通常是完全解析后的文件名。
  5. module.loaded:模块是否已经加载完成,或正在加载中。
  6. module.parent:最先引用该模块的模块。
  7. module.paths:模块的搜索路径。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值