深入理解Commonjs规范及Node模块实现

2020-06-17 06:46:25易采站长站整理

实际上,.node的模块文件并不需要编译,因为它是编写C/C++模块之后编译生成的,所以这里只有加载和执行的过程。在执行的过程中,模块的exports对象与.node模块产生联系,然后返回给调用者

C/C++模块给Node使用者带来的优势主要是执行效率方面的,劣势则是C/C++模块的编写门槛比JavaScript高

【JSON文件的编译】

.json文件的编译是3种编译方式中最简单的。Node利用fs模块同步读取JSON文件的内容之后,调用JSON.parse()方法得到对象,然后将它赋给模块对象的exports,以供外部调用

JSON文件在用作项目的配置文件时比较有用。如果你定义了一个JSON文件作为配置,那就不必调用fs模块去异步读取和解析,直接调用require()引入即可。此外,你还可以享受到模块缓存的便利,并且二次引入时也没有性能影响

 CommonJS

在介绍完Node的模块实现之后,回到头来再学习下CommonJS规范,相对容易理解

CommonJS规范的提出,主要是为了弥补当前javascript没有标准的缺陷,使其具备开发大型应用的基础能力,而不是停留在小脚本程序的阶段

CommonJS对模块的定义十分简单,主要分为模块引用、模块定义和模块标识3个部分

【模块引用】


var math = require('math');

在CommonJS规范中,存在require()方法,这个方法接受模块标识,以此引入一个模块的API到当前上下文中

【模块定义】

在模块中,上下文提供require()方法来引入外部模块。对应引入的功能,上下文提供了exports对象用于导出当前模块的方法或者变量,并且它是唯一导出的出口。在模块中,还存在一个module对象,它代表模块自身,而exports是module的属性。在Node中,一个文件就是一个模块,将方法挂载在exports对象上作为属性即可定义导出的方式:


// math.js
exports.add = function () {
var sum = 0, i = 0,args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};

在另一个文件中,我们通过require()方法引入模块后,就能调用定义的属性或方法了


// program.js
var math = require('math');
exports.increment = function (val) {
return math.add(val, 1);
};

【模块标识】

模块标识其实就是传递给require()方法的参数,它必须是符合小驼峰命名的字符串,或者以.、..开头的相对路径,或者绝对路径。它可以没有文件名后缀.js

模块的定义十分简单,接口也十分简洁。它的意义在于将类聚的方法和变量等限定在私有的作用域中,同时支持引入和导出功能以顺畅地连接上下游依赖。每个模块具有独立的空间,它们互不干扰,在引用时也显得干净利落