接触到node后对于node中可以自由使用module和exports感到很神奇,再加上自己碰到的一些问题,做了一些总结,先抛出自己的一些问题:
场景1:
const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
console.log(error);
});
client.on("connect", ()=>{
console.log("redis connect successful");
});
console.log(this); //{}
console.log(exports);//{}
console.log(module.exports);//{}
module.exports=client;
console.log(this);//{}
console.log(exports);//{}
console.log(module.exports);// RedisClientObj
场景2
const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
console.log(error);
});
client.on("connect", ()=>{
console.log("redis connect successful");
});
console.log(this); //{}
console.log(exports);//{}
console.log(module.exports);//{}
exports=client;
console.log(this);//{}
console.log(exports);//RedisClientObj console.log(module.exports);// {}
场景3
const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
console.log(error);
});
client.on("connect", ()=>{
console.log("redis connect successful");
});
console.log(this); //{}
console.log(exports);//{}
console.log(module.exports);//{}
exports.result=client;
console.log(this);//{'result':RedisClientObj}
console.log(exports);//{'result':RedisClientObj}
console.log(module.exports);// {'result':RedisClientObj}
这个模块就是简单引入redis,这里redis不是重点,可以忽略,关键点是之后的那些console
查询了很多资料后,感觉以上的问题可以归咎为2点:
1.node模块执行时帮我们做了什么操作
2.函数参数的传递是值传递还是引用传递
别急,喝口水,让我一步步往下讲。
首先关键是要弄清楚,你写了一个模块以后,node做了什么封装操作,以上面的代码为例:
let module={"id":"module_id","exports":{},"path_name":"path_name","children":"children"};
let getResult=function(exports,module){
//开始自己模块的代码
const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
console.log(error);
});
client.on("connect", ()=>{
console.log("redis connect successful");
});
module.exports=client;
//自己代码块结束
return module.exports;
}
let exported = getResult.call(module.exports,module.exports,module);
从上面看来,node会为我们先准备一个module对象,然后把他当作函数的参数传进来,由于使用了call,导致函数体内的this就会指向module.exports,而传进去的参数又是module.exports和module。
接着在函数体内,我们就可以使用module和exports这两个参数了,这里要注意的是,这里传参是值传递,即该对象的内存地址,不是引用传递!
然后我们先来看场景1:
通过上面代码可以很清楚知道,开始实际上module.exports和exports是指向同一个对象,而this开始又是指向module.exports,所以开始的三个console出来都是空对象。之后开始对module.exports赋值,这里要注意了,我们使用的module,实际上是传进来的参数,是外面定义那个module对象的地址,现在我们对module.exports赋值,如此一来,module里面这个exports的地址指向已经变了,指向了另一块内存,而由于是值传递,this和exports保存的仍然是之前的内存地址,所以他们仍然为{}
再看场景2:
同样的道理,这次对exports赋值,也只有exports会变化,而this和module.exports还是指向之前的内存地址。
场景3:
这里的赋值是对exports.res来说的,这里并没有开辟新的内存去覆盖exports,只是在exports上新加了一个属性罢了,所以exports的内存地址没有改变,最后三个打印出来都是被赋了值的对象。
以上只是自己的一些总结,欢迎指正。