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

所以你对此是怎么做的?传统方法告诉我们,最好的消除全局策略是创建少数作为潜在模块和子系统的实际命名空间的全局对象。
我将探索几种有关命名空间的方式,并以我基于 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. 二分LIS模板

    假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5. 下面一步一步试着找出它. 我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列. ...

  2. Codeforces Round #306 (Div. 2) A. Two Substrings【字符串/判断所给的字符串中是否包含不重叠的“BA” “AB”两个字符串】

    A. Two Substrings time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  3. vue编程中,需要注意的

    同名情况: data() 中的数据名   和  methods()  中的方法名  不能相同. 原因:因为在vue中这两个都能用this.XX拿出来,如果写一样的,将不能分辨,计算机会默认覆盖一个. ...

  4. Jboss ESB简介及开发实例

    一.Jboss ESB的简介 1. 什么是ESB.         ESB的全称是Enterprise Service Bus,即企业服务总线.ESB是过去消息中间件的发展,ESB采用了“总线”这样一 ...

  5. javap -c 字节码含义

    aconst_null         将null对象引用压入栈 iconst_m1         将int类型常量-1压入栈 iconst_0         将int类型常量0压入栈 icons ...

  6. springmvc使用StringHttpMessageConverter需要配置编码

    Spring controller 如下 @Controller public class SimpleController { @ResponseBody @RequestMapping(value ...

  7. 用gulp+webpack构建多页应用——记一次Node多页应用的构建过程

    通过参考网上的一些构建方法,当然也在开发过程中进行了一番实践,最终搭建了一套适用于当前多页应用的构建方案,当然该方案还处于draft版本,会在后续的演进过程中不断的优化. 个人觉得该方案的演进过程相对 ...

  8. 【GitHub】README.md文件中 markdown语法 插入超链接

    语法: [Spring-data-jpa 查询 复杂查询陆续完善中](http://www.cnblogs.com/sxdcgaq8080/p/7894828.html) [文本](URL) 效果:

  9. selenium 自动化测试 测试报告 生成

    https://www.cnblogs.com/yoyoketang/p/6140439.html https://www.cnblogs.com/testyao/p/5658200.html 一.下 ...

  10. 使apache的日志文件里不记录图片文件

    找到: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-A ...