CommonJS规范
CommonJS使用exports导出模块,require导入模块。exports是一个空对象,require是一个函数,参数传入模块的路径即可返回该模块导出的整个内容。
导出:
// 要隐藏的内部实现
let abc = 1;
// 要暴露给外部的接口
function test(){
abc++;
return abc;
}
// exports = {}
exports.test = test;
/*
exports: {
test: fn
}
*/
exports.a = 456;
/*
exports: {
test: fn
abc: 456
}
*/
导入:
// node.js中导入模块,使用相对路径,并且必须以./或../开头
const utils = require('./utils.js');
console.log(utils.abc);// 456;
NodeJS对CommonJS的实现
-
为了保证高效的执行,仅加载必要的模块,NodeJS只有执行到require函数时才会加载并执行模块。
-
为了隐藏模块中的代码,NodeJS执行模块时,会将模块中的所有代码放置到一个函数中执行,以保证不污染全局变量。
(function(){
// 模块中的代码
})()
-
为了保证顺利的导出模块内容,nodejs做了以下处理
-
在模块开始执行前,初始化一个值module.exports = {},module.exports即模块的导出值
-
为了方便开发者便捷的导出,nodejs在初始化完module.exports后,又声明了一个变量exports = module.exports
-
(function(module){
module.exports = {};
var exports = module.exports;
//模块中的代码
return module.exports;
})()
- 为了避免反复加载同一个模块,nodejs默认开启了模块缓存,如果加载的模块已经被加载过了,则会自动使用之前的导出结果。
一些坑
CommonJS导出的是module.exports。我们也可以直接给module.exports重新赋值一个对象。
console.log(module.exports === exports); // true
module.exports = {
test: function(){
console.log('test');
},
abc: 123
}
// 由于给module.exports重新赋值为一个新对象,
// 而exports还是原来的{}。地址不一样所以不相等。
console.log(module.exports === exports); // false
// 导出
module.exports = {
test: function(){
console.log('test');
},
abc: 123
}
exports.abc = 456;
// 导入
const test = require('./utils');
console.log(test.abc); // 123
module.exports 可以直接赋值,但是exports直接赋值,导出的还是一个空对象。
// 可以直接赋值
module.exports = '123';
// exports直接赋值
exports = '123'; // 导出还是为空对象