Node
Node.js 是一个基于"Chrome V8 引擎" 的JavaScript “运行环境”,其基本使用不再赘述。
node模块
NodeJS采用CommonJS规范实现了模块系统
node模块导出数据的几种方式:
1.通过exports.xxx = xxx导出
2.通过module.exports.xxx = xxx导出
3.通过global.xxx = xxx导出
但是:
无论通过哪种方式导出, 使用时都需要先导入(require)才能使用
通过global.xxx方式导出不符合CommonJS规范, 不推荐使用
实现原理
我们先对模块原理进行分析:
node模块:
1.在CommonJS规范中一个文件就是一个模块
2.在CommonJS规范中通过exports暴露数据
3.在CommonJS规范中通过require()导入模块
既然一个文件就是一个模块,那么我们要想使用就必须先通过require()导入模块,所以可以推断出require()的作用其实就是读取文件,那么要想了解Node是如何实现模块的, 必须先了解如何执行读取到的代码。
执行文件
若是通过fs读取文件,得到的将是二进制文件或字符串,但都无法直接执行,但是我们知道如果是字符串, 在JS中是有办法让它执行的:eval 或者 new Function;
通过eval执行代码和new Function执行代码:
缺点: 存在依赖关系, 字符串可以访问外界数据,不安全
通过NodeJS的vm虚拟机执行代码:
runInThisContext: 无权访问外部变量, 但是可以访问global
runInThisContext提供了一个安全的环境给我们自行字符串中的代码,不能访问本地的变量, 但是可以访问全局的变量(也就是global上的变量)
runInNewContext: 无权访问外部变量, 也不能访问global
runInNewContext提供了一个安全的环境给我们执行字符串中的代码,不能访问本地的变量, 也不能访问全局的变量(也就是global上的变量)
加载分析
通过对实现原理的分析,现在我们可以对它的加载进行逐步分析与实现了。
我们通过webstorm等IDE或浏览器对其执行过程进行监控,得到如下加载流程:
1.内部实现了一个require方法
function require(path) {
return self.require(path);
}
2.通过Module对象的静态__load方法加载模块文件
Module.prototype.require = function(path) {
return Module._load(path, this, /* isMain */ false);
};
3.通过Module对象的静态_resolveFilename方法, 得到绝对路径并添加后缀名
var filename = Module._resolveFilename(request, parent, isMain);
4.根据路径判断是否有缓存, 如果没有就创建一个新的Module模块对象并缓存起来
var cachedModule = Module._cache[filename];
if (cachedModule)