全局变量应该由有系统范围相关性的对象们保留,并且它们的命名应该避免含糊并尽量减少命名冲突的风险。
在实践中,这意味着你应该避免创建全局对象,除非它们是绝对必须的。

所以你对此是怎么做的?传统方法告诉我们,最好的消除全局策略是创建少数作为潜在模块和子系统的实际命名空间的全局对象。
我将探索几种有关命名空间的方式,并以我基于 James Edwards 最近的一篇文章得到的一个优雅、安全和灵活的解决方案结束。

静态命名空间
我用静态命名空间作为那些命名空间标签实际上硬编码的解决方案的涵盖性术语。是的,你可以将一个命名空间重新分配给另一个,
不过新的命名空间将会引用和旧的那一个同样的对象。

1.通过直接分配
最基础的方法。这样非常冗长,并且如果你还想重命名这些命名空间,你就有得活儿干了。不过它是安全和清楚明白的。

var myApp = {}
myApp.id = ;
myApp.next = function() {
return myApp.id++;
}
myApp.reset = function() {
myApp.id = ;
}
window.console && console.log(
myApp.next(),
myApp.next(),
myApp.reset(),
myApp.next()
); //0, 1, undefined, 0

你也可以通过使用this引用兄弟属性来使将来的维护更轻松一些,不过这有一点冒险因为没有什么能阻止你的那些命名空间里的方法被重新分配。

var myApp = {}
myApp.id = ;
myApp.next = function() {
return this.id++;
}
myApp.reset = function() {
this.id = ;
}
myApp.next(); //
myApp.next(); //
var getNextId = myApp.next;
getNextId(); //NaN whoops!

2.使用对象字面量
现在我们只需要引用命名空间名一次,因此之后改变名字更简单了一些(假设你还没反复引用这个命名空间)。
仍有一个危险是this的值可能会抛出一个『惊喜』 – 不过假设在一个对象字面结构里定义的对象不会被重新分配相对安全一点。

var myApp = {
id: ,
next: function() {
return this.id++;
},
reset: function() {
this.id = ;
}
}
window.console && console.log(
myApp.next(),
myApp.next(),
myApp.reset(),
myApp.next()
) //0, 1, undefined, 0

3.模块模式
我发现自己最近用模块模式更多。逻辑被一个方法包装从全局域隔离开了(通常是自调用的),它返回一个代表这个模块公开接口的对象。
通过立即调用这个方法并分配结果给一个命名空间变量,我们就锁住了这个命名变量中模块的 API。
此外,任何没有包括在返回值中的变量将永远保持私有,只对引用他们的公开方法可见。

var myApp = (function() {
var id= ;
return {
next: function() {
return id++;
},
reset: function() {
id = ;
}
};
})();
window.console && console.log(
myApp.next(),
myApp.next(),
myApp.reset(),
myApp.next()
) //0, 1, undefined, 0

如上对象字面量例子,命名空间名字可以轻易更换,不过还有额外优势:对象字面量是四班的 – 它全是关于属性分配,
没有支持逻辑的空间。此外,所有属性必须被初始化,并且属性值无法轻易跨对象引用(因此,比如,内部闭包就不可能使用了)。
模块模式没有任何上述约束,并且给我们额外的隐私福利。

动态命名空间
我们也可以将这一节称为命名空间注入。命名空间由一个直接引用方法包装内部的代理代表 – 这意味着我们不再需要打包分配给命名空间的返回值。
这让命名空间定义变得更灵活并且让拥有多个存在于独立命名空间中(或者甚至在全局上下文中)的模块的独立实例。
动态命名空间支持模块模式的全部特征并附加直观和可读性强的优势。

4.提供命名空间参数
在这里我们只是将命名空间作为参数传给自调用方法。变量id是私有的,因为他并没有被分配给context。

var myApp = {};
(function(context) {
var id = ;
context.next = function() {
return id++;
};
context.reset = function() {
id = ;
}
})(myApp);
window.console && console.log(
myApp.next(),
myApp.next(),
myApp.reset(),
myApp.next()
) //0, 1, undefined, 0

我们甚至可以把context设置给全局对象(通过一个字的改变!)。这是库主们的巨大财富 – 他们可以将他们的特性包装在一个自调用函数中,
然后让用户来决定它们是不是全局的(John Resig 在他写 JQuery 时就是一个这个理论的早期采用者)。

var myApp = {};
(function(context) {
var id = ;
context.next = function() {
return id++;
};
context.reset = function() {
id = ;
}
})(this);
window.console && console.log(
next(),
next(),
reset(),
next()
) //0, 1, undefined, 0

5.用this作为命名空间代理
James Edwads 最近发布的一篇文章激起了我的兴趣。《My Favorite JavaScript Design Patter》 显然被很多评论者误解了,
他们认为他可能也是借助于模块模式。这篇文章宣传了多种技术(可能导致了读者的迷惑),
但是在它的核心部分是一点我已经修改并呈现为一个命名空间工具的很天才的东西。
这个模式的美就在于它仅仅是按照这个语言被设计的方式使用 – 不多不少、不投机也不取巧。
此外因为命名空间是通过this关键字(它在给定的执行上下文中是不变的)注入的,它不可能被意外修改。

var myApp = {};
(function() {
var id = ; this.next = function() {
return id++;
}; this.reset = function() {
id = ;
}
}).apply(myApp); window.console && console.log(
myApp.next(),
myApp.next(),
myApp.reset(),
myApp.next()
); //0, 1, undefined, 0

更棒的是,apply(以及call) API 提供了与上下文和参数天然的隔离 – 因此给模块创建者传递附加参数非常干净。
下面的例子表明了这一点,并且展示了如何独立于多个命名空间来运行模块。

var subsys1 = {}, subsys2 = {};
var nextIdMod = function(startId) {
var id = startId || ;
this.next = function() {
return id++;
};
this.reset = function() {
id = ;
}
};
nextIdMod.call(subsys1);
nextIdMod.call(subsys2,);
window.console && console.log(
subsys1.next(),
subsys1.next(),
subsys2.next(),
subsys1.reset(),
subsys2.next(),
subsys1.next()
) //0, 1, 1000, undefined, 1001, 0

当然如果我们如果我们需要一个全局 id 生成器,非常简单……

nextIdMod();
window.console && console.log(
next(),
next(),
reset(),
next()
) //0, 1, undefined, 0

这个我们作为例子使用的 id 生成器工具并没有表现出这个模式的全部潜力。通过包裹一整个库和使用this关键字作为命名空间的替身,
我们使得用户在任何他们选择的上下文中运行这个库很轻松(包括全局上下文)。

//library code
var protoQueryMooJo = function() {
//everything
}
//user code
var thirdParty = {};
protoQueryMooJo.apply(thirdParty);

其他的考虑
我希望避免命名空间嵌套。它们很难追踪(对人和电脑都是)并且它们会让你的代码因为一些乱七八糟的东西变得很多。
如 Peter Michaux 指出的,深度嵌套的命名空间可能是那些视图重新创建他们熟悉和热爱的长包链的老派 Java 开发者的遗产。

通过 .js 文件来固定一个单独的命名空间也是可以的(虽然只能通过命名空间注入或者直接分配每一个变量),不过你应该对依赖谨慎些。
此外将命名空间绑定到文件上可以帮助读者更轻易弄清整个代码。

因为 JavaScript 并没有正式的命名空间结构,所以有很多自然形成的方法。
这个调查只详细说明了其中的一部分,可能有更好的技术我没有发现。我很乐意知道它们。

JavaScript 中的命名空间的更多相关文章

  1. JavaScript中创建命名空间

    引用:http://ourjs.com/detail/538d8d024929582e6200000c   在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺 ...

  2. 在JavaScript中创建命名空间的几种写法

    在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺序来的,可以看看下面的例子: var sayHello = function() { return 'Hel ...

  3. JavaScript中的this陷阱的最全收集

    JavaScript来自一门健全的语言,所以你可能觉得JavaScript中的this和其他面向对象的语言如java的this一样,是指存储在实例属性中的值.事实并非如此,在JavaScript中,最 ...

  4. JavaScript中的匿名函数及函数的闭包

    1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...

  5. JavaScript中function的多义性

    JavaScript 中的 function 有多重意义.它可能是一个构造器(constructor),承担起对象模板的作用: 可能是对象的方法(method),负责向对象发送消息.还可能是函数,没错 ...

  6. JavaScript中的this陷阱的最全收集 没有之一

    当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概 念,可能真解释不清楚.有句话这么说:如果你不能向一个6岁小孩解 ...

  7. 理解JavaScript中的作用域和上下文

    JavaScript对于作用域(Scope)和上下文(Context)的实现是这门语言的一个非常独到的地方,部分归功于其独特的灵活性. 函数可以接收不同的的上下文和作用域.这些概念为JavaScrip ...

  8. JavaScript中的闭包和匿名函数

    JavaScript中的匿名函数及函数的闭包   1.匿名函数 2.闭包 3.举例 4.注意 1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没 ...

  9. 转:JavaScript中的this陷阱的最全收集

    在其他地方看到的,觉得解释的狠详细,特此分享 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清 ...

随机推荐

  1. 陕西师范大学第七届程序设计竞赛网络同步赛 C iko和她的糖【贪心/ STL-优先队列/ 从1-N每个点有能量补充,每段有消耗,选三个点剩下最多能量】

    链接:https://www.nowcoder.com/acm/contest/121/C来源:牛客网 题目描述 iko超级超级喜欢吃糖,有一天iko想出去玩,她计划从1点走到N点(按1,2,3,.. ...

  2. NYOJ 71 乘船问题【贪心】

    时间复杂度O(n) 有n个人,第i个人的重量为w[i],每艘船的最大载重量均为c,且最多只能乘两个人.用最少的船装载所有人. 思路:从最轻的开始考虑,让最轻的和最重的一条船,若超出重量则可判定最重的只 ...

  3. Codeforces Round #445 D. Restoration of string【字符串】

    D. Restoration of string time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  4. 后门构建工具Backdoor Factory

    后门构建工具Backdoor Factory   在渗透测试中,后门程序帮助渗透测试人员在目标机器上执行各种预期的操作.例如,它可以建立从目标主机到攻击机的网络连接,方便渗透测试人员控制目标主机.Ka ...

  5. Lowest Common Ancestor of a Binary Search Tree -- LeetCode

    Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...

  6. MVC中的Controller中返回一个JsonResult在弹出一个下载框?

    public JsonResult ReturnTest() { return Json(new {myMsg ="hello world"}, "text/html; ...

  7. WPF程序中的弱事件模式

    在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源.但是,GC有的时并不是按照我们所期望的方式工作. 例如,我想实现一个在窗口的标题 ...

  8. 使用 SQL Server 的 uniqueidentifier 字段类型

    原文:使用 SQL Server 的 uniqueidentifier 字段类型 SQL Server 自 2008 版起引入了 uniqueidentifier 字段,它存储的是一个 UUID, 或 ...

  9. 设计模式之空对象模式(php实现)

    github地址:https://github.com/ZQCard/design_pattern /** * 在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象 ...

  10. 设计模式之责任链模式(php实现)

    github地址:https://github.com/ZQCard/design_pattern /** * 责任链模式(Chain of Responsibility Pattern)为请求创建了 ...