首页 > 代码库 > JavaScript基础对象创建模式之命名空间(Namespace)模式(022)

JavaScript基础对象创建模式之命名空间(Namespace)模式(022)

JavaScript中的创建对象的基本方法有字面声明(Object Literal)和构造函数两种,但JavaScript并没有特别的语法来表示如命名空间、模块、包、私有属性、静态属性等等面向对象程序设计中的概 念。为了让JavaScript实现面向对象程序中的高级语义,人们发明了命名空间模式、依赖声明模式,模块模式,以及沙盘模式。

1. 命名空间模式
命 名空间模式解决了JavaScript中的两个问题,一是全局变量污染的问题,二是可能的名字冲突问题。虽然JavaScript没有特别支持命名空间, 但命名空间模式在JavaScript中并不难实现。为了不过多使用全局变量,可以把程序中所有使用到的全局变量组织到一个(最好是一个程序只有一个)全 局的对象中去。接下来,要访问需要的变量,就可以通过这个对象来得到引用:
// BEFORE: 5 globals// Warning: antipattern// constructorsfunction Parent() {}function Child() {}// a variablevar some_var = 1;// some objectsvar module1 = {};module1.data = http://www.mamicode.com/{a: 1, b: 2};>
上面的代码里有5个全局变量,有全局的对象,也有全局的简单类型的变量。下面建立一个全局对象,名字比如说叫MYAPP,然后把上面的5个全局变量都组织到MYAPP里:
// AFTER: 1 global// global objectvar MYAPP = {};// constructorsMYAPP.Parent = function () {};MYAPP.Child = function () {};// a variableMYAPP.some_var = 1;// an object containerMYAPP.modules = {};// nested objectsMYAPP.modules.module1 = {};MYAPP.modules.module1.data = http://www.mamicode.com/{a: 1, b: 2};>

 

这个全局对象的名字,可以选择使用程序的名字,也可以用域名,也可以用公司名。通常这个全局对象的名字是全大写的,以便看起来醒目些,但它并不是常量(常量通常也是全大写的)。
这种模式可以很好的解决命名冲突的问题,因为不同程序或公司的代码里使用的变量,都被组织到不同的全局对象中,因此许多JavaScript的库都是用这种方式来组织API的。但这种模式也有些小问题:
  • 变量使用起来需要敲更多的字母,js文件也因此变得更大;
  • 只有一个全局变量使得所有的代码都可以使用它并修改它,这种修改可以即时生效;
  • 长的嵌套的名字使得变量的解析过程需要更长的时间。
后面还将介绍的沙盘模式将应对这些问题。
2. 通用的命名空间函数
当程序变得越来越大之后,使用这个变量之前才在全局对象中声明它变得不再安全:一些属性和对象可能已经在全局对象中存在,重新声明它将把它原有的内容覆盖,因此我们在声明变量时就需要先做个简单的检查:
// unsafevar MYAPP = {};// betterif (typeof MYAPP === "undefined") {    var MYAPP = {};}// or shortervar MYAPP = MYAPP || {};
上面的检查是简单有效的,但十分繁琐: 在使用MYAPP.modules.module2这前,需要做3次检查。因此就需要有一个叫namespace()的函数,在每次使用声明一个模块或变量之前,做相应的检查:
// using a namespace functionMYAPP.namespace(‘MYAPP.modules.module2‘);// equivalent to:// var MYAPP = {//     modules: {//         module2: {}//     }// };
下面就是一个通用的namespace()函数的实现:
var MYAPP = MYAPP || {};MYAPP.namespace = function (ns_string) {    var parts = ns_string.split(‘.‘),        parent = MYAPP,        i;    // strip redundant leading global    if (parts[0] === "MYAPP") {        parts = parts.slice(1);    }    for (i = 0; i < parts.length; i += 1) {        // create a property if it doesn‘t exist        if (typeof parent[parts[i]] === "undefined") {            parent[parts[i]] = {};        }        parent = parent[parts[i]];    }    return parent;};
有了上面的namespace()函数,我们就可以这样做了:
// assign returned value to a local varvar module2 = MYAPP.namespace(‘MYAPP.modules.module2‘);module2 === MYAPP.modules.module2; // true// skip initial `MYAPP`MYAPP.namespace(‘modules.module51‘);// long namespaceMYAPP.namespace(‘once.upon.a.time.there.was.this.long.nested.property‘);
这样我们就声明了一个很长的嵌套命名空间:
JavaScript基础 022 - 对象创建模式之命名空间(Namespace)模式 - zihui.lin - Zihui的空间
 

JavaScript基础对象创建模式之命名空间(Namespace)模式(022)