module原理
在学习nodejs,首先是看了廖雪峰老师的nodejs教程,因为它比较短,比较容易系统看一遍来入门。
快速的过了一遍,module
原理感觉是其中一个重点。
模块化可以解决javascrip全局变量污染的问题,而且模块化也比较符合软件工程的要求。
nodej通过CommonJS
规范实现模块化,什么是CommonJS
规范后续需要单独学习学习。
nodejs通过module.exports
来暴露模块。
通过require
来引入模块。
假设我写了个sum.js
模块用来计算参数a
和参数b
的和
function sum(a,b){
return a+b;
}
module.exports = sum;
当我通过require
来引用模块的时候,nodejs把sum.js
的代码放到一个load
函数中
var module = {
id: 'hello',
exports: {}
};
var load = function (exports, module) {
// sum.js的文件内容开始
function sum(a,b){
return a+b;
}
module.exports = sum;
//sum.js的文件内容结束
// load函数返回:
return module.exports;
};
下面是我的猜测了,require
函数返回的就是load
函数的执行结果,require
当然会做很多事,比如加载js文件等,这里就做一个模拟,可能还是错的
function require(moduleName){
if(moduleName==="sum.js"){
return load(module.exports,module);
}
throw "没有找到模块:"+moduleName;
}
在调用文件中,可以通过require
来调用sum.js
模块了
var sum = require("sum.js");
var sumResult = sum(1,1);
console.log(sumResult);
所有代码合在一起
var module = {
id: 'hello',
exports: {}
};
var load = function (exports, module) {
// sum.js的文件内容开始
function sum(a,b){
return a+b;
}
module.exports = sum;
//sum.js的文件内容结束
// load函数返回:
return module.exports;
};
function require(moduleName){
if(moduleName==="sum.js"){
return load(module.exports,module);
}
throw "没有找到模块:"+moduleName;
}
var sum = require("sum.js");
var sumResult = sum(1,1);
console.log(sumResult);
其中廖雪峰老师提到
如果要输出一个键值对象
{}
,可以利用exports
这个已存在的空对象{}
,并继续在上面添加新的键值;如果要输出一个函数或数组,必须直接对
module.exports
对象赋值。所以我们可以得出结论:直接对
module.exports
赋值,可以应对任何情况。
这里我卡了好一会,直到验证了这个事实
var a = {};
function test1(a1){
a1 = {
b:1
}
return a;
}
function test2(a2){
a2.b = 1;
return a;
}
console.log(test1(a));//{}
console.log(test2(a));//{b:1}
c语言指针,引用,传值,传址,传引用等基础知识还是能够帮助理解的。
所以
var module = {
id: 'hello',
exports: {}
};
var load = function (exports, module) {
// sum.js的文件内容开始
function sum(a,b){
return a+b;
}
//module.exports = sum;
//注意这里,改成了用exports而不是module.exports
//形参exports与实参module.exports指向同一个{}
//通过形参exports给{}中加了sum这个键和函数sum这个值
//module.exports同样也指向了这个{}
//所以通过module.exports.sum可以拿到函数sum
exports.sum = sum;
//sum.js的文件内容结束
// load函数返回:
return module.exports;
};
function require(moduleName){
if(moduleName==="sum.js"){
return load(module.exports,module);
}
throw "没有找到模块:"+moduleName;
}
//这里要变了
var sum = require("sum.js").sum;
var sumResult = sum(1,1);
console.log(sumResult);
而想像最开始那样直接返回sum函数,通过exports是做不到的
var module = {
id: 'hello',
exports: {}
};
var load = function (exports, module) {
// sum.js的文件内容开始
function sum(a,b){
return a+b;
}
//module.exports = sum;
//形参exports指向了sum函数,但是实参module.exports依然指向{}
exports = sum;
//sum.js的文件内容结束
// load函数返回:
return module.exports;
};
function require(moduleName){
if(moduleName==="sum.js"){
return load(module.exports,module);
}
throw "没有找到模块:"+moduleName;
}
var sum = require("sum.js");
var sumResult = sum(1,1);//抛异常:sum不是一个函数
console.log(sumResult);
再来看一遍
如果要输出一个键值对象
{}
,可以利用exports
这个已存在的空对象{}
,并继续在上面添加新的键值;如果要输出一个函数或数组,必须直接对
module.exports
对象赋值。所以我们可以得出结论:直接对
module.exports
赋值,可以应对任何情况。
嗯,理解了。
可惜暂时在入门阶段,
没有耐心去读源码,
这个加载module的执行过程是通过廖雪峰老师的教程和自己的猜想合成的,
后续看了源码再来修正吧。