九、在JavaScript当中定义命名空间

我们人类的语言是有限的,为了方便管理同名但功能不同的函数,高级语言当中都引入了命名空间的概念,但是在JS当中是没有这一概念的,这次我们来仿造一个命名空间出来,可能健壮性不是很强,但可以作为一个学习的参考。

本文捎带复习JS面向对象的基本知识,以及F12脚本调试器的使用方法介绍。

我们人类的语言是有限的,为了方便管理同名但功能不同的函数,高级语言当中都引入了命名空间的概念,但是在JS当中是没有这一概念的,这次我们来仿造一个命名空间出来,可能健壮性不是很强,但可以作为一个学习的参考。

本文捎带复习JS面向对象的基本知识,以及F12脚本调试器的使用方法介绍。

首先直接贴代码:

 

function DefineNamespace(name) {
    if (!name) { return null; }
    var level = name.split(".");
    var floder = window[level[0]] = window[level[0]] || {};
    for (var i = 1; i < level.length; i++) {
        floder = floder[level[i]] = floder[level[i]] || {};
    }
}

DefineNamespace("MyNamespace.IO");
MyNamespace.IO.Read = function () {
    alert("test");
}

MyNamespace.IO.Read();

 

这段代码在下面的运行部分首先定义了一个名为“MyNamespace.IO”的命名空间,然后为其添加Read函数,最后调用这个函数。

关注一下DefineNamespace这个函数,第一行不解释,第二行的作用是将MyNamespace.IO拆成两部分。值得关注的是第三行代码:

 

var floder = window[level[0]] = window[level[0]] || {};

为了解释这行代码做了什么,我们可以打开IE自带的F12开发人员工具,对浏览器*对象window下的MyNamespace添加监视,并打上几个断点,操作如图:

九、在JavaScript当中定义命名空间

按F10单步调试,当代码走过第三行时,floder被赋值了一个空对象:

九、在JavaScript当中定义命名空间

在这一行代码当中我们看到了两个等号,即A=B=C的形式,那么程序会先执行B=C,将结果赋值给A。

先来看最右边的{},这是Javascript定义对象的方式,以下两行代码是等效的:

 

var myObj = new Object();
var myObj = {};

而window[level[0]]中的level[0]就是上面取到的"MyNamespace",window[level[0]]是取浏览器*对象window当中的"MyNamespace"子对象,我们在上面的图中可以看到这个对象一开始是空的。

所以“window[level[0]] || {}”这部分就表示先找window下有没有"MyNamespace"对象,如果没有就返回一个空对象,有就返回它自身,这样做的目的是防止第二次创建同名命名空间把第一次盖掉,如果真的同名了,就返回原来的对象,这种手段可以理解为一种单例模式。

最后把返回的命名空间对象交给floder变量,它是"MyNamespace"对应的根元素,也就是在第二张途中看到的这个空Object,这个元素被挂在了window对象当中,可以供我们调用。

然后看接下来的for循环:

for ( var i = 1; i < level.length; i++) {
     floder = floder[level[i]] = floder[level[i]] || {};
}

首先i是从1开始的,也就是说,从“IO”这个子层开始的,因为对象可以通过[]这种索引器取子对象,所以这里同理先判断命名空间根元素下有没有IO这个元素,如果没有则将IO对象添加到根元素下。接下来添加第二层、第三层……

当执行完第一次后,可以看到在根元素下已经有IO对象了:

九、在JavaScript当中定义命名空间

紧跟着调用后面的方法定义:

九、在JavaScript当中定义命名空间

在这样,就能通过MyNamespace.IO.Read();的方式调用命名空间下的函数了。

这段代码在下面的运行部分首先定义了一个名为“MyNamespace.IO”的命名空间,然后为其添加Read函数,最后调用这个函数。

关注一下DefineNamespace这个函数,第一行不解释,第二行的作用是将MyNamespace.IO拆成两部分。值得关注的是第三行代码:

var floder = window[level[0]] = window[level[0]] || {};

为了解释这行代码做了什么,我们可以打开IE自带的F12开发人员工具,对浏览器*对象window下的MyNamespace添加监视,并打上几个断点,操作如图:

九、在JavaScript当中定义命名空间

按F10单步调试,当代码走过第三行时,floder被赋值了一个空对象:

九、在JavaScript当中定义命名空间

在这一行代码当中我们看到了两个等号,即A=B=C的形式,那么程序会先执行B=C,将结果赋值给A。

先来看最右边的{},这是Javascript定义对象的方式,以下两行代码是等效的:

var myObj = new Object();
var myObj = {};

而window[level[0]]中的level[0]就是上面取到的"MyNamespace",window[level[0]]是取浏览器*对象window当中的"MyNamespace"子对象,我们在上面的图中可以看到这个对象一开始是空的。

所以“window[level[0]] || {}”这部分就表示先找window下有没有"MyNamespace"对象,如果没有就返回一个空对象,有就返回它自身,这样做的目的是防止第二次创建同名命名空间把第一次盖掉,如果真的同名了,就返回原来的对象,这种手段可以理解为一种单例模式。

最后把返回的命名空间对象交给floder变量,它是"MyNamespace"对应的根元素,也就是在第二张途中看到的这个空Object,这个元素被挂在了window对象当中,可以供我们调用。

然后看接下来的for循环:

for ( var i = 1; i < level.length; i++) {
     floder = floder[level[i]] = floder[level[i]] || {};
}

首先i是从1开始的,也就是说,从“IO”这个子层开始的,因为对象可以通过[]这种索引器取子对象,所以这里同理先判断命名空间根元素下有没有IO这个元素,如果没有则将IO对象添加到根元素下。接下来添加第二层、第三层……

当执行完第一次后,可以看到在根元素下已经有IO对象了:

九、在JavaScript当中定义命名空间

紧跟着调用后面的方法定义:

九、在JavaScript当中定义命名空间

在这样,就能通过MyNamespace.IO.Read();的方式调用命名空间下的函数了。