Node.js相关——CommonJS规范

1. CommonJS规范产生背景

在后端,JavaScript的规范远远落后而且有不少缺陷,这使得难以使用JavaScript开发大型应用。好比:html

  • 没有模块系统
  • 标准库较少
  • 没有标准接口
  • 缺少包管理系统

CommonJS规范 的提出,主要是为了弥补JavaScript没有标准的缺陷。CommonJS API将经过定义处理许多常见应用程序需求的API来填补这一空白,最终提供与Python,Ruby和Java同样丰富的标准库。以达到像Python、Ruby和Java那样具有开发大型应用的基础能力,而不是停留在开发浏览器端小脚本程序的阶段。node

应用程序开发人员可以使用CommonJS API编写应用程序,而后跨不一样的JavaScript解释器和主机环境运行该应用程序。json

2. CommonJS模块规范

CommonJS模块规范主要分为三部分:模块引用、模块定义、模块标识。后端

2.1 模块引用

//引入http模块,并赋值给变量http
var http = require('http');

require函数的基本功能是,读入并执行一个JavaScript文件,而后返回该模块的exports对象。当咱们用require()获取module时,Node会根据module.id找到对应的module,并返回module. exports,这样就实现了模块的输出。api

require函数使用一个参数,参数值能够带有完整路径的模块的文件名,也能够为模块名。数组

require("./module/b"); //相对路径
require("../node/module/c");  //绝对路径

文件目录结构以下:浏览器

2.2 模块定义

2.2.1 模块(module)是什么

CommonJS规范规定,一个文件就是一个模块,用module变量表明当前模块。 Node在其内部提供一个Module的构建函数。全部模块都是Module的实例。实例代码以下:服务器

function Module(id, parent) {
  this.id = id; this.exports = {}; this.parent = parent; this.filename = null; this.loaded = false; this.children = []; } module.exports = Module; var module = new Module(filename, parent);

每一个模块内部,都有一个module对象,表明当前模块。它的属性以下:网络

  • module.id 模块的识别符,一般是带有绝对路径的模块文件名。
  • module.filename 模块的文件名,带有绝对路径。
  • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
  • module.parent 返回一个对象,表示调用该模块的模块。
  • module.children 返回一个数组,表示该模块要用到的其余模块。
  • module.exports 初始值为一个空对象{},表示模块对外输出的接口。

2.2.2 exports 属性

exports 属性是module对象的一个属性,它向外提供接口。
如 2.1模块引用 中示例,a.js引入b.js做为一个模块,当在b.js中定义以下方法时:异步

//加法
function add(num1,num2){
    console.log(num1+num2);
}

在a.js中调用却报错

var addMethod = require("./module/b");
//调用模块中的add方法
addMethod.add(1,6);

b.js中的函数要能被其余模块使用,就须要暴露一个对外的接口,exports 属性用于完成这一工做。b.js中的方法定义修改以下:

exports.add = function(num1,num2){
    console.log(num1+num2);
}

在a.js中可以调用。

2.3 模块标识

模块标识就是传递给require方法的参数,必须符合小驼峰命名的字符串,或者以.、..开头的相对路径,或者绝对路径,默认文件名后缀.js。在Node实现中,正是基于这样一个标识符进行模块查找的,若是没有发现指定模块会报错。

根据参数的不一样格式,require命令去不一样路径寻找模块文件。加载规则以下:

(1)若是参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。好比,require('/home/marco/foo.js')将加载/home/marco/foo.js。

(2)若是参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。好比,require('./circle')将加载当前脚本同一目录的circle.js。

(3)若是参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。

举例来讲,脚本/home/user/projects/foo.js执行了require('bar.js')命令,Node会依次搜索如下文件。

/usr/local/lib/node/bar.js

/home/user/projects/node_modules/bar.js

/home/user/node_modules/bar.js

/home/node_modules/bar.js

/node_modules/bar.js

这样设计的目的是,使得不一样的模块能够将所依赖的模块本地化。

(4)若是参数字符串不以“./“或”/“开头,并且是一个路径,好比require('example-module/path/to/file'),则将先找到example-module的位置,而后再以它为参数,找到后续路径。

(5)若是指定的模块文件没有发现,Node会尝试为文件名添加.js、.json、.node后,再去搜索。.js件会以文本格式的JavaScript脚本文件解析,.json文件会以JSON格式的文本文件解析,.node文件会以编译后的二进制文件解析。

(6)若是想获得require命令加载的确切文件名,使用require.resolve()方法。

CommonJS是同步的,意味着你想调用模块里的方法,必须先用require加载模块。这对服务器端的Nodejs来讲不是问题,由于模块的JS文件都在本地硬盘上,CPU的读取时间很是快,同步不是问题。但若是是浏览器环境,要从服务器加载模块。模块的加载将取决于网速,若是采用同步,网络情绪不稳定时,页面可能卡住,这就必须采用异步模式。因此,就有了 AMD解决方案。下一篇咱们开始介绍模块化规范的AMD规范;

 

参考:

https://www.cnblogs.com/huiguo/p/7967241.html

https://nodejs.org/api/modules.html#modules_module_exports

相关文章
相关标签/搜索