模块的工作原理
实现“模块”功能的奥妙就在于JavaScript是一种函数式编程语言,它支持闭包。如果我们把一段JavaScript代码用一个函数包装起来,这段代码的所有“全局”变量就变成了函数内部的局部变量。
模块的加载顺序
模块加载按照如下顺序从先到后:优先从缓存加载--> 核心模块 --> 路径形式的文件模块 --> 第三方模块
优先从缓存加载
有以下三个js,终端运行node main.js会出现什么样的结果?
//a.js
console.log('a.js 被加载了')
var fn = require('./b')
console.log(fn)
//b.js
console.log('b.js 被加载了')
module.exports = function (str) {
console.log('hello'+str)
}
//main.js
require('./a')
var fn = require('./b')
fn(",Mary")
优先从缓存加载,由于在a.js
中已经加载过b.js
了,所以在main.js
中不会重复加载b.js
。可以拿到其中的接口对象,但是不会重复执行里面的代码。这样做的目的是为了避免重复加载,提高模块加载效率。
最终运行结果为:
a.js 被加载了
b.js 被加载了
[Function]
hello,Mary
核心模块
- 核心模块就是NodeJS的标准API
- 核心模块的本质也是文件
- 核心模块文件已经被编译到了二进制文件中了,只需要按照名字来加载就可以了,例如
require('fs')
路径形式的文件模块
也就是自己写的模块,在该模块中通过exports或者module.exports导出模块对象,两者是有差别的,真正使用的时候一般按照如下规则:
- 导出多个成员:
exports.xxx = xxx
- 导出多个成员也可以:
module.exports = {}
- 导出单个成员:
module.exports
通过require可以加载自己写的模块,有以下的一些规定
./ 当前目录,不可省略。如果省略,就不是一个相对路径,那么Node.js将该文件视为node_modules目录下的一个文件
../ 上一级目录,不可省略
.js 后缀名可以省略
第三方模块
通过npm安装进项目的模块即为第三方模块,他的加载书写规则和核心模块一模一样,但是加载的时候,nodejs会先去核心模块加载,没有该模块则去第三方木块加载
它的加载原理如下所列:
- index.js 备选项
- 进入上一级目录找 node_modules
- 按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx
一个项目有且仅有一个 node_modules 而且是存放到项目的根目录