第一部分 模块的简单介绍
在介绍模块之前还是得提一下JavaScript缺少这些功能:
- JavaScript没有模块系统。没有原生的支持密闭作用域或依赖管理。
- JavaScript没有标准库。除了一些核心库外,没有文件系统的API,没有IO流API等。
- JavaScript没有标准接口。没有如Web Server或者数据库的统一接口。
- JavaScript没有包管理系统。不能自动加载和安装依赖。
于是便有了CommonJS规范的出现,其目标是为了构建JavaScript在包括Web服务器,桌面,命令行工具,及浏览器方面的生态系统。
CommonJS制定了解决这些问题的一些规范,而Node.js就是这些规范的一种实现。
模块是对某个功能的封装,Node中模块与文件是一一对应的;我们用两个数的相加为例子, 来展示Node中模块的定义与使用方式:《以下两个js文件在同一目录下》
模块add.js, 实现的功能是传入两个数,返回和;
//add.js
exports.addTwo = function(x, y){
return x + y;
};
调用模块add.js,求两个数的和
//calculate.js
//只需要require需要调用的文件即可
var calTwoNum = require('./add.js');
var sum = calTwoNum.addTwo(1, 2);
console.log(sum);
打印的结果
$ node calculate.js
3
非常简单的定义出口(export)与引用(require);那么封装与调用就会非常简单.
第二部分 内部实现
抱着知其然还得知其所以然的态度, 模块是怎么被引用的呢??
2.1 模块加载
2.1.1模块的分类
* 原生(核心)模块: 在Node.js源代码编译的时候编译进了二进制执行文件,加载的速度最快。
* 位置: 在源代码 lib/ 之中
* 如:http;
*
* 文件模块: 动态加载的,加载速度比原生模块慢。
* 如自己封装的模块;
*
* 总的一点, node都将他们进行了缓存;
*
require() 总是会优先加载核心模块。例如,require('http') 总是返回编译好的 HTTP 模块,而不管这个文件的名字。
1.模块的前缀没有的, require('http'), 可能是 core module.
2模块的前缀'/' 表示绝对路径, 例如 require('/home/marco/foo.js') 将会加载 /home/marco/foo.js文件。
3.模块的前缀'./' 表示相对路径, add.js和.calculate.js在同一目录下;
4.require() 的模块不是一个本地模块,并且不以 '/', '../', 或 './' 开头,那么 Node 会从当前模块的父目录开始,尝试在它的 node_modules 文件夹里加载模块。
例如:如果 '/home/ry/projects/foo.js' 里的文件加载 require('bar.js'),那么 Node 将会按照下面的顺序查找:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
深入Node.js的模块机制
2.2 如何繁杂的加载顺序, 如何确保效率?
模块第一次加载后会被被缓存。这就是说,每次调用 require('add') 都会返回同一个对象,当然,必须每次都要解析到同一个文件。
多次调用 require('add') 也许不会导致模块代码多次执行。
第三部分 模块对象
1.module.children, 该模块引用的对象, 是一个数组类型;
2.module.exports: 模型系统提供的方法, 方法出口;
3.module.filename{String}:模块完全解析的文件名。
4.module.loaded: {Boolean}
模块是已经加载完毕,还是在加载中。
5.module.parent: {Module Object}
引入这个模块的模块。
参考链接
深入Node.js的模块机制
Node.js官方文档
Node.js官方中文文档-极客学院
更多精彩内容请关注“IT实战联盟”哦~~~
IT实战联盟.jpg
网友评论