命名空间
所谓的命名空间说白了就是避免名字冲突. (www.hedaoshe.com)
假如全世界没有国家, 班级, 学校等概念. 有两个员工叫张三,老板喊了一句:张三过来扫厕所. 两个张三都会去扫厕所. 这就造成了冲突. 但如果一个张三是清华大学的, 另一个张三是北京大学的. 这时候老板喊: 北京大学那个张三过来扫厕所. 那么就不会造成混淆了.
编程语言的命名空间就是用来区分不同对象(万物皆对象,包括基础数据类型),这样就不会造成混淆.
闭包
很多语言都有包的概念进行命名空间的管理, 比如java,php等. 但js是没有包概念的. js实现命名空间管理是使用闭包的概念.
正常情况下,js只有全局变量和局部变量.全局变量全部绑定到终极对象window上面, 而局部变量在函数执行完成后会被销毁. 但如果我们让一个全局变量指向一个对象,window.$={}
. 那么该对象就是命名空间, 里面的变量虽然是局部变量, 但是因为有全局变量引用,所以并不会被销毁.
下面例子 a,b,c变量都是直接绑定到window上面. 对于c变量,你可以调用c.b()而不会和b()冲突. 那是因为c变量指向的是一个封闭的对象. 这个对象就是一个命名空间.
window={}
var window.a='aaa'
var window.b=function(){return 'bbb'}
var window.c={a:'ccc',b:function(){return 'ddd'}}//重点注意
闭包只是命名空间的实现而已,没什么稀奇的.
下面例子 就是一个闭包, 先定义一个匿名函数, 再立马执行. 传入了window对象作为参数. 当执行完毕后, window对象就有了$属性, 并绑定了一个对象.
window = {};
(function(win){
win.$={
a:'ccc',
b:function(){return 'ddd'}
}
})(window)
console.log(window)
//{ '$': { a: 'ccc', b: [Function: b] } }
如果你导入一个对象并赋值给window对象的属性,不用闭包也是一样!
global
js有window全局对象,nodejs有global全局对象.
我们知道nodejs引入外部模块格式const hello=require('./hello')
, 其实正真的格式是:
global = {}
const global.hello=require('./hello')
也就是说你导入的文件被global下的一个属性引用, 和js下的window引用属性无任何区别.
exports vs module.exports
重头戏来了,很多人搞不清楚exports和module.exports的区别,它们都可以用来导出模块.下面我们来分析过程.
const path=require('path')
这句话其实是调用global的require方法,根据路径找到文件,并把文件实例化一个对象绑定到global.path的属性下面.
//假如下面就是文件的对象,我们在对象里定义了三个方法a,b,c
{
//global实例化该文件时把内部参数封装到module中,这个我们不用管.只需要知道有个exports={}属性
let module={
exports={}
}
let exports=module.exports
//我们定义的函数
function a(){return 'aaa'}
function b(){return 'bbb'}
function c(){return 'ccc'}
//我们需要导出什么直接赋值
module.exports.a=a
module.exports.b=b
exports.c=c
//最终返回的就是它
return module.exports
//最后返回{a函数,b函数,c函数}
}
上面
let exports=module.exports
就是重点, 这也就是为什么我们通过添加属性的方式导出, module.exports和exports是等价的. 但是下面这种方式只有module.exports有效,exports是无效的.
{
let module={
exports={}
}
let exports=module.exports
function a(){return 'aaa'}
function b(){return 'bbb'}
function c(){return 'ccc'}
exports=a
return module.exports
//最后返回空对象{}
}
原因解析: 因为exports变量一开始指向module.exports, 但
exports=c
直接修改了exports变量的指向, 它不再指向于module.exports. 我们根本没有对module.exports做任何操作,所以最后返回的还是一个空对象, 并不是a函数.
结束语
看完这篇文章,相信大家对于exports和module.exports有了深入理解,可喜可贺可喜可贺