javascript“命名空间”的费曼输出[原创]
Javascript由于没有命名空间的概念,所以好多的框架或库就用了某些“命名空间”的技巧。在学习作为函数的命名空间时,我翻阅了好多的书本和blog,很多的概念和说明都是要么过于烦杂或过于简单。现在由我来进行一个的系统的描述和介绍。
一、浏览器启动后的初步理解
1.我们要上网,就要打开浏览器,输入网址,浏览器就负责渲染和相应用户的鼠标动作。而打开浏览器这个进程后,浏览器的网络线程负责解析网址为ip地址,去网页服务器下载网页文件到本地硬盘,我就称这个线程是network线程;另外一个线程是负责解析网页文件的html和css代码,渲染界面,我就称这个线程是view线程;还有一个线程是负责解析javascript的代码,我称这个线程是js虚拟机线程,该js虚拟机线程会根据Window构造函数,实例化一个window对象。注意这个Window和window是不同的,Window是一坨在未运行的代码,而window是加载到js虚拟机里的“活”的代码,简称实例。
二、所谓的js全局变量和函数都是建立在浏览器window这个进程里
下面的这些是我们常规写js的代码例子:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> alert('hello'); </script> </html> |
这个例子里面alert是一个警告函数,它的对象是window,以上的代码也能改写为如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> window.alert('hello'); </script> </html> |
我们通过打开浏览器的F12,在source下的Watch输入window这个实例,就能观察到alert这个函数是在window下的
下一步,我们改造下上面的代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var aaa={}; </script> </html> |
上面定义了个aaa的这个变量,它的类型是Object,刷新上面的watch跟踪,就能看到aaa是window实例下的一个属性值了。
下面我又添加了个function
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var aaa={}; function a_fun(){ console.log('a_fun'); }
</script> </html> |
刷新watch如下:
可以总结出,在<script></script>里面定义的变量和函数,都是挂接在window下的,成为了window实例的属性。
三、js要引入所谓“命名空间”这个概念背后的原因
我一直在baidu和查资料,搜索到结果都是为了避免变量名字冲突,造成不必要的异常。对此,我的理解是如下:
1、为了避免名称冲突,人类好聪明,考虑到了用字母加符号的方式来拼接,形式可以是如下表:
car-bmw-china 中横杠式 car_bmw_china 下横杠式 carBmwChina 驼峰式 car.bmw.china 点连式 |
2、为何“命名空间”基本是趋于“点连式”呢?原因写代码的程序员都习惯了java的包的命名规律,所以自然而然就考虑使用这个方式。另外javascript也是支持obj.xxx这种属性或方法访问的,所以“xxx.yyy.zzz”会被聪明的程序员成为“命名空间”。
3、命名空间最后的简化,我理解就是window下的某个用户自定义的变量,这个变量的类型是Object
四、几种“命名空间”的建立演示(含代码和window的watch截图)
1、对象式的定义法1:定义aaa.index的命名空间,此空间下包含login和submit的方法
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var aaa={};//创建aaa这个“命名空间” --[实际是aaa的Object的对象] aaa.index={};//这个是在aaa"命名空间",建立aaa.index这个对象 aaa.index.login=function(){ //为aaa.index.login绑定一个匿名函数 console.log('login'); }; aaa.index.submit=function(){ //为aaa.index.submit绑定一个匿名函数 console.log('submit'); };
</script> </html> |
在控制台下就能访问到aaa.index这个“命名空间”了,实际它就是一个aaa.index的对象
2、对象式的定义法2:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var aaa={ index:{ login:function(){ console.log('login'); }, submit:function(){ console.log('submit'); }, }, };
</script> </html> |
截图如下:
*由于以上2种对象定义法虽然能引入“命名空间”的效果,但是,在分析代码时,不便于分析哪些是业务用的变量,哪些是“命名空间”的变量。所以聪明的程序员就用了某些技巧如匿名函数运行来创建容易理解的“命名空间”
3、匿名函数运行后的“命名空间”演示:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var aaa={}; aaa.index=function(){ //其实是简化了aaa.index={} return { login:function(){ console.log('login'); }, submit:function(){ console.log('submit'); }, }; }(); </script> </html> |
这段代码里面用到了function(){}()这个匿名函数的执行语句,核心是那个return返回了个对象,对象里面有login和submit这2个绑定了实际匿名函数的方法。
但上面的方式还是不太直观,因为java的程序里面,最前面是引用的各类命名空间包的,鉴于此,有些高手的程序员对上面的定义做了如下的改造,自动按照命名空间字符串来建立“命名空间”对象:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var $={};//这个是一个普通对象,只是以$号为命名而已。 $.namespace = function() { //这个是$这个变量的一个方法,用途是自动按照输入的字符串参数返回“命名空间”对象 var a=arguments, o=null, i, j, d; for (i=0; i<a.length; i=i+1) { d=a[i].split("."); o=window; for (j=0; j<d.length; j=j+1) { o[d[j]]=o[d[j]] || {}; o=o[d[j]];//把新产生的对象加入window实例。 } } return o; }; $.namespace('aaa.index');//作用是建立aaa.index这个"命名空间"对象 aaa.index={ login:function(){ console.log('login'); }, submit:function(){ console.log('submit'); }, };
</script> </html> |
因为核心的代码,
aaa.index={ login:function(){ console.log('login'); }, submit:function(){ console.log('submit'); }, }; |
有时会被人误认为定义对象,所以会用function(){return {}}()来包裹上面的定义代码,为的是为后面维护代码的人知道这个是“命名空间”的代码,
于是按上面的规律,代码变成如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>title</title> </head> <body> <h1>hello world</h1> </body> <script> var $={};//这个是一个普通对象,只是以$号为命名而已。 $.namespace = function() { //这个是$这个变量的一个方法,用途是自动按照输入的字符串参数返回“命名空间”对象 var a=arguments, o=null, i, j, d; for (i=0; i<a.length; i=i+1) { d=a[i].split("."); o=window; for (j=0; j<d.length; j=j+1) { o[d[j]]=o[d[j]] || {}; o=o[d[j]];//把新产生的对象加入window实例。 } } return o; }; $.namespace('aaa.index');//作用是建立aaa.index这个"命名空间"对象 aaa.index=function(){ return { login:function(){ console.log('login'); }, submit:function(){ console.log('submit'); }, }; }();
</script> </html> |
五、我的初步总结:
1、javascript是没有“命名空间”的概念的,这个概念只是参考了java等面向对象语言的概念做到名字变量的不冲突。
2、Javascript的function(){}()包裹的“命名空间”代码只是方便后期维护代码时,不会看成是普通json式对象的定义而已。
3、Javascript的核心根本是基于window线程虚拟机的编程。