1. 写在前面
对象在JS中是一个引用类型,其中保存的是存储其属性的内存空间地址,与指针类似
将一个对象赋值给另一个对象其实是赋值了内存地址,此时这两个对象都可以通过保存的内存地址对内存数据进行更改,一个对象属性的更改就必然会引起另一个对象属性的变化
2. 例子1
bar.js :
//node中一个文件就是一个模块
const name= 'Harry';
let age = '18';
message = 'lulu lala';
function sayHello(){
console.log('Hello' + name)
}
//在每一个模块里有一个全局对象exports
//默认是一个空对象,在内存中会开辟一个空间,exports实际保存的是存储其属性的内存地址,
//想把谁导出,就把谁作为exports的属性
exports.age = age;
exports.name = name;
exports.sayHello = sayHello();
//实际导出的其实是module.exports对象,node源码中进行了一步对象的引用赋值 module.exports = exports
module.exports.message = message;
setTimeout(()=>{
console.log(exports.name) //hhhh
},2000)
main.js :
//这一步其实是将module.exports 对象赋值给了 bar对象
const bar = require('./bar')
console.log(bar.sayHello);//HelloHarry
console.log(bar.name);//Harry
console.log(bar.age);//18
console.log(bar.message);//lulu lala
setTimeout(()=>{
bar.name = 'hhhh'
},1000)
上述代码其实等于如下图所示
module.exports 对象 exports对象 bar对象存储的都是同一个内存地址,所以一个对象属性的变化会引起另外两个的变化
这时候可能有人要问,既然最后导出的是module.exports,还要exports干嘛?
原因是在CommonJS规范内,强调要有一个exports导出的用法,有人学了CommonJS, 要是没有exports,他就会发现怎么exports在node里不能用了,这显然不可以。
为了验证最后导出的是module.exports我们来看例子2
3. 例子2
bar.js:
const name = 'Harry';
const age = '18';
exports.name = name;
exports.age = age;
module.exports = {message: 'hello'}
main.js :
const bar = require('./bar')
console.log(bar) //{message: 'hello'}
有人可能要问不是module.exports = exports 吗,因为这里module.exports被赋值了一个新的内存地址, 这时module.exports 和bar 里面的内存地址就和exports内的内存地址没关系了
也就是说现在的内存图是这样:
4. 例子3
再来个例子
main.js:
let bar = require('./bar');
setTimeout(()=>{
bar = 'hhhh'
},1000)
bar.js:
module.exports = '123'
setTimeout(()=>{
console.log(module.exports)//123
},2000)
这里为什么还是123呢?
因为JS中字符串是一个值类型,赋值时会把值的拷贝赋值,所以bar此时修改的只是值的拷贝,和原本值无关
5. 例子4
最后一个例子
main.js :
let bar = require('./bar');
setTimeout(()=>{
bar.info.height = '1.70'
},1000)
bar.js :
const name = 'Harry';
const info = {
height: '1.80'
}
module.exports.name = name;
module.exports.info = info;
setTimeout(()=>{
console.log(module.exports.info.height)//1.70
},2000)
这个关系图就是这样
代码main.js中通过bar 的内存地址,获取到info的内存地址,修改了info的属性, 所以bar中的的info属性也得到修改