node.js模块化&commonJS规范

node.js模块化&commonJS规范

nodejs与commonjs

nodejs主要用于服务端编程,文件一般都能够本地读取速度较快,采用的是同步加载的commonjs规范。

关于commonjs:

  • 每个文件都是封闭的一个模块,模块里定义的变量、函数、类都是私有的
  • module代表当前模块,module是封闭的,但它的exports属性向外提供调用接口
  • require加载模块,读取并执行一个js文件,然后返回该模块的exports对象
  • commonjs是同步加载的,因此模块加载的顺序严格按照代码书写的顺序执行
  • 模块可以多次加载,但在第一次加载之后模块会被编译执行,放入缓存,后续的require直接从缓存里取值,模块代码不再编译执行

require内部处理流程

  • 检查Module._cache是否缓存了指定模块
  • 如果缓存没有的话,就创建一个新的module实例将它保存到缓存
  • module.load()加载指定模块
  • 在解析的过程中如果发生异常,就从缓存中删除该模块
  • 返回该模块的module.exports

模块化导出方式

  • module.exports = "str";//可以
  • module.exports.msg = 'str'//可以
  • exports.msg = 'str'//可以
  • exports = 'str'//不行

关于最后一个导出方式为什么不行的说明:
module是封闭的模块,属性、函数都是私有的,仅对外提供module.exports属性以供调用,而require加载函数的返回值永远是module.exports属性对象,因为exports引用关系改变不再指向module.exports,与module.exports再无瓜葛,所以无法被require识别调用

模块化原理

module的封闭性,模块的隔离怎么实现?

利用JavaScript函数式编程的特性,采用自执行函数实现隔离。

模块化的输出怎么实现?

node在加载js文件之前先准备一个module对象
module对象{id:'jsfilename',exports:{}}
在加载的时候,把js文件加载进load函数,module作为load函数的形参传进去,最后把js文件的对象保存在module.exports属性中并返回
在require获取module时,只要传入对应的id找到对应的module,就可以在Node中拿到对应module的exports对象,完成模块的输入与输出
代码如下:

// 准备module对象:
var module = {
    id: 'hello',
    exports: {}
};
var load = function (module) {
    // 读取的hello.js代码:
    function greet(name) {
        console.log('Hello, ' + name + '!');
    }
    
    module.exports = greet;
    // hello.js代码结束
    return module.exports;
};

var exported = load(module);
// 保存module:
save(module, exported);

案例

// a.js
exports.x = 'a1';
console.log('a.js ', require('./b.js').x);
exports.x = 'a2';

// b.js
exports.x = 'b1';
console.log('b.js ', require('./a.js').x); 
exports.x = 'b2';

// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);

输出: a1 b2 a2 b2
分析:
前提:commonjs模块的加载是严格同步的且在第一次加载时编译代码并存入缓存,后续加载直接从缓存读取

  • 执行main.js第一行,首次加载并执行a.js并将a加入缓存
  • a.js中require b.js,此时a被阻塞,需要等待b编译加载并执行完成,此时a的缓存写入了x为a1
  • b.js中require a,由于a的已经被main.js第一次加载,此刻读取缓存中a的exports为a1
  • b.js打印a1,随后b将x=b2写入缓存,b首次加载完成,此时a.js等待完毕,将x=a2写入缓存,a首次加载完毕
  • main.js中,a打印a编译、加载完毕之后x的值,a2。main.js第二行,由于b.js已经存在于缓存中,于是直接从缓存中读取x为b2并打印
  • 综上,打印结果为a1,b2,a2,b2

node.js模块

主要基于commonJS规范,包括内置模块、自定义模块、第三方模块

内置模块

node自身携带的模块
例如:require('http');require('path');require('url');

自定义模块

require函数的形参path中用相对路径或者绝对路径导入的模块
在本地实现,通过module.exports导出

第三方模块

主要是npm的一些开源的包,当然你也可以发布自己的包

猜你喜欢

转载自www.cnblogs.com/ltfxy/p/12507833.html