commonJs模块
不久前,看到火狐在5月份将宣布支持js模块化,即会引入import,export方法。我自己一直都没有用过模块化的插件,比如commonJs,AMD,CMD,这些库的概念倒是都讲的是模块化操作,也就是模块化的编程。因为webpack具有这些插件的所有功能,并且更加强大,所以没有去了解这些插件库,其实webpack是怎样模块化的,我也搞不清楚,都是按照命令行操作,内部的实现没去弄学习,也没研究源码。
模块化的好处:
功能的复用,写好的功能,可以直接通过模块引入,文件划分也清楚明了。
大文件可以拆分为很多个模块,便于管理和维护。
以前需要某个js插件的功能,就用script标签加载这个js 文件,有的时候就会加载很多个文件。script标签的加载是同步的,浏览器会停止渲染,同步加载这些js文件,这样会增加浏览器的响应时间。
多个文件的命名冲突,全局变量的污染。
以前解决变量命名冲突的方法有,使用闭包,使用对象命名空间。
//a.js
var obj_a= {
test:1,
say:function(){
alert(1);
}
}
//b.js
var obj_b={
test:"str",
say:function(){
alert(144444);
}
}
var moudle=(function(){
var a= 1;
function say(){
console.log(34)
}
return {a:a,say:say};
CommonJS 模块,nodejs用的这个规范
模块定义导出
通过exports 或modules.exports导出模块,也就是定义模块。注意es6用的是export,不能直接给exports赋值,并且es6有 export {...} ,node里不可以 exports {...};切记不能弄混了。
//a.js
const a = 1;
let fun1 = function (x,y){
return x + y ;
}
exports.a = a ;
exports.fun1 = fun1;
//注意 exports {a,fun1}; 不对,es6有 export {a,fun1},但是es6 不能export.a = a,这样导出。
//或
module.exports = {a , fun1};
在上面的例子中 ,exports 指向的就是module.exports;当使用模块化的时候,就已经声明 var expoets = module.exports = {};其中module指的就是当前的模块。打印出module就可以看到
Module {
id: '.',
exports: {"a":1,"fun1":[Function]},
parent: null,
filename: '/Users/zss/node-Demo/my-app/testNOde/b.js',
loaded: false,
children: [],
paths:
[ '/Users/zss/node-Demo/my-app/testNOde/node_modules',
'/Users/zss/node-Demo/my-app/node_modules',
'/Users/zss/node-Demo/node_modules',
'/Users/zss/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
exports 是node 提供的一个变量指向module.exports,用来收集一些属性最后赋值给module.exports .这样一来,当我们在exports里导出变量a,再用module.exports 导出变量a,最后的结果是moudle.exports 的变量a.总之模块最终调用额是module.exports。
模块的分类,有两种模块
一类为原生模块,例如http、path,加载的时候不用指明路径直接加载,速度很快。
一类为文件模块,动态加载的模块,也就是需要导入或是自己写。引入的时候需要指定模块的路径
这两种模块加载的时候都会被缓存,也就是说第一次引用会加载,在引用的时候就会取缓存里的。
模块的加载机制————模块的引用规则
node的加载流程
找目录下的文件名,然后加上扩展名称,依次按照“ .js .node .json”查找,.node 和.json文件加上后缀名会快些。
已上面的a.js 为例, 当找到a.js,首先读取内容包上一层function,避免暴露于全局中,这个function闭包有五个参数:exports,require,module,_filename,\_dirname_
(function(exports,require,module,__filename,__dirname){
const a = 1;
let fun1 = function (x,y){
return x + y ;
}
exports.module= {a,fun1};
});
这就为什么在可以在js文件里直接用 require ,exports ,module,__dirname,__filename.
node是读取缓存的,可以用如下的图来描述:

CommonJs规范比较适合服务器端,浏览启端的需要异步加载,所以就有了CMD、AMD规范。
注意当导出一个模块的变量时,是对这个模块变量的缓存复制,也就是说模块块内的变量发生改变时,不影响导出的变量,读取的是缓存里的。这一点与es6的模块机制不同。
// a,js
let a = 1;
let b = {"name":"str"};
const fun1 = function(){
a++;
return a ;
};
exports.a=a;
exports.fun1=fun1;
exports.b=b;
//或
module.exports={a,fun1};
b={test:"change"};
mpdule.exports.b.name == "str" // true 没改变
//b.js
const obj = require("./a.js");
obj.fun1();//2
console.log(obj.a) // 1 没变
Last updated
Was this helpful?