模块
CommonJS规范
CommonJS是一种思想,它的终极目标是使应用程序开发者根据CommonJS API编写的JavaScript应用可以在不同的JavaScript解析器和HOST环境上运行。目前,有四大平台支持CommonJS API:Rhino、Spidermonkey、v8、JavaScriptCore。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎
引入
- 模块的引入大大提高了代码的可维护性并避免函数名和变量名冲突
- 在node.js中文件和模块是一一对应的,即每个文件被视为一个独立的模块;模块分为两种类型:原生模块和文件模块
- Node提供了exports和require两个对象,其中exports是模块公开的接口,require用于从外部获取一个模块接口,即所获取模块的exports对象
原生模块(核心模块)
原生模块在Node.js源代码编译的时候编译进了二进制执行文件,加载的速度最快
在这不具体介绍,有兴趣可参考https://itbilu.com/nodejs/core/N1tv0Pgd-.html
文件模块
文件模块中,又分为3类模块。这三类文件模块以后缀来区分,Node.js会根据后缀名来决定加载方法。
.js。通过fs模块同步读取js文件并编译执行。
.node。通过C/C++进行编写的Addon。通过dlopen方法进行加载。
.json。读取json文件,调用JSON.parse解析加载。
在路径 Y 下执行 require(X) 语句执行顺序:
1. 如果 X 是一个核心模块,
a. 返回核心模块
b. 结束
2. 如果 X 是以 '/' 开头(绝对路径)
a. 设 Y 为文件系统根目录
3. 如果 X 是以 './' 或 '/' 或 '../' 开头(相对路径)
a. 加载文件(Y + X)
b. 加载目录(Y + X)
4. 加载Node模块(X, dirname(Y))
5. 抛出 "未找到"
加载文件(X)
1. 如果 X 是一个文件,加载 X 作为 JavaScript 文本。结束
2. 如果 X.js 是一个文件,加载 X.js 作为 JavaScript 文本。结束
3. 如果 X.json 是一个文件,解析 X.json 成一个 JavaScript 对象。结束
4. 如果 X.node 是一个文件,加载 X.node 作为二进制插件。结束
加载索引(X)
1. 如果 X/index.js 是一个文件,加载 X/index.js 作为 JavaScript 文本。结束
3. 如果 X/index.json 是一个文件,解析 X/index.json 成一个 JavaScript 对象。结束
4. 如果 X/index.node 是一个文件,加载 X/index.node 作为二进制插件。结束
加载目录(X)
1. 如果 X/package.json 是一个文件,
a. 解析 X/package.json,查找 "main" 字段
b. let M = X + (json main 字段)
c. 加载文件(M)
d. 加载索引(M)
2. 加载索引(X)
加载Node模块(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. 加载文件(DIR/X)
b. 加载目录(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = "node_modules" CONTINUE
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS
require
require函数用于在当前模块中加载和使用别的模块,传入一个模块名,返回一个模块导出对象。require方法接受以下几种参数的传递:
http、fs、path等。原生模块。(优先载入)
./mod或../mod。相对路径的文件模块。
/a/mod,绝对路径的文件模块。
mod,非原生模块的文件模块。
export
module.export与export
每一个node.js执行文件,都自动创建一个module对象,同时,module对象会创建一个叫exports的属性,初始化的值是 {}
exports是引用 module.exports的值。module.exports 被改变的时候,exports不会被改变,而模块导出的时候,真正导出的执行是module.exports,而不是exports
exports在module.exports 被改变后,失效。
通过exports = module.exports的方法,让其恢复原来的特点。
/*
module.exports.example1=function () {
console.log(1);
}
exports = module.exports;
*/
exports.a=function () {
console.log('a');
}
module.exports.a = function () {
console.log(2)
}
module.exports是真正的接口,exports只不过是它的一个辅助工具。 最终返回给调用的是Module.exports而不是exports。
所有的exports收集到的属性和方法,都赋值给了module.exports,而前提是module.exports本身不具备任何属性和方法。如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。