Skip to content

nodejs 中的模块化

模块分类

内置模块

  • node.js 官方提供的内置模块,加载优先级最高
  • 即使存在第三方模块名称相同,始终返回内置模块

自定义模块(用户创建的.js 文件)

  • 加载自定义模块 require,要以./../路径标识符开头,否则会被当做内置或第三方模块
  • 使用 require() 导入自定义模块时,若省略文件扩展名,则 Node.js 会按顺序分别尝试加载以下的文件
  • 确切的文件名称 => 补全.js 扩展名加载 => 补全.json 扩展名加载 => 补全.node 扩展名加载 => 加载失败,报错

第三发模块(由第三方开发的模块,使用前需要下载依赖)

  • 优先在当前模块的父目录,尝试从 node_modules 文件夹中加载第三方模块
  • 若当前目录下没找到,则移动到上一层父目录,直至文件夹的根目录

加载模块

js
// 加载内置的模块
const fs = require("fs");
// 加载用户自定义模块
const custom = require("./custom.js");
// 加载第三方模块
const moment = requrie("moment");

TIP

使用 require() 方法加载其它模块时,会执行被加载模块中的代码

优先从缓存中加载

  • 模块在第一次被加载后会被缓存,之后即使多次调用 require,不会导致模块代码被执行多次
  • 不论是内置模块、用户自定义模块、第三方模块,都会优先从缓存中加载

文件目录作为加载模块

  • 在被加载的目录下找到 package.json 文件,寻找 main 属性,作为加载的入口
  • 如果没有 package.json 文件,或者 main 入口不存在或者解析失败,则尝试加载根目录下的 index.js 文件
  • 上面两种不通则会报错

模块作用域

类似函数作用域,自定义模块中定义的成员、方法名等,只能在当前模块内访问。

custom.js

js
const username = "jack";
function Hello() {
  console.log("hello nodejs");
}

main.js

js
const custom = require("./custom.js");
// custom中没有暴露,无法访问其中的私有变量
console.log(custom); //{}

好处: 防止全局变量污染

向外共享模块中的对象或变量

1. module 对象

每个.js 自定义模块中都有一个 module 对象,存储了和当前模块有关的信息

js
Module{

...
id:'',
exports:{}
...

}

2. module.exports

共享模块内的变量、对象,供外界使用。外界用 require()导入得到 module.exports所指向的对象

注意点:

使用 require() 方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准

custom.js

js
module.exports.username = 'tom'
module.exports.fn1 = (){
  console.log('hello nodejs')
}
module.exports = {
  username:'jack',
  fn2(){
    console.log('hi react')
  }
}

main.js

js
const custom  require('./custom.js')
console.log(custom)// {username:jack, fn2:[Function: fn2]}

3. exports

为了简化向外共享成员的代码,默认和 module.exports 指向同一个对象.区别在于它公开的是它指向的对象的属性

4. exports 和 module.exports

最终指向结果永远以 module.exports 指向为准,以下示例:

js
exports.name = "jack";

module.exports = {
  sex: "man",
  age: 23,
};
// 引用结果:{sex:'man',age:23}
js
module.exports.name = "jack";

exports = {
  sex: "man",
  age: 23,
};
// 引用结果:{name:'jack'}
js
exports.name = "jack";

module.exports.sex = "man";
// 引用结果:{sex:'man',name:'jack'}

注意

为了防止混乱,建议不要在同一个模块中同时使用 exports 和 module.exports