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

所以你对此是怎么做的?传统方法告诉我们,最好的消除全局策略是创建少数作为潜在模块和子系统的实际命名空间的全局对象。
我将探索几种有关命名空间的方式,并以我基于 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. 微信小程序 使用swiper制作一个滑动导航

    最近在做一个导航的时候,发现使用overflow-x: auto来做多内容滑动导航效果很不好,思索是不是可以使用swiper来做一个,研究了下其实发现原理基本相同 这里说下,要用swiper做导航菜单 ...

  2. Codeforces Gym 101775D Mr. Panda and Geometric Sequence(2017-2018 ACM-ICPC Asia East Continent League Final,D题,枚举剪枝)

    题目链接  ECL-Final 2017 Problem D 题意  给定$2*10^{5}$组询问,每个询问求$l$到$r$之间有多少个符合条件的数 如果一个数小于等于$10^{15}$, 并且能被 ...

  3. Ngnix 安装与使用

    高性能web服务器-ngnix MySQL读写分离技术 sphinx和mongodb 课程内容简介 一般都是拿nginx作为负载均衡器使用.Apache还是web市场老大.全球的市场份额大概在(60% ...

  4. [Python Cookbook] Pandas: Indexing of DataFrame

    Selecting a Row df.loc[index] # if index is a string, add ' '; if index is a number, no ' ' or df.il ...

  5. 【bzoj2160】【啦啦队排练】manacher(马拉车)+差分+快速幂

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=34562780 向大(hei)佬(e)势力学(di ...

  6. C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)

    https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC ...

  7. canvas实现"雷达扫描"效果

    今天来讲解“雷达扫描”效果demo,来源于QQ群里边有群友说想要个雷达效果,就尝试写了一下. 效果图: demo链接: https://win7killer.github.io/can_demo/de ...

  8. Go -- 升级go版本

    先卸载go的旧版本, 参考卸载go; 然后用brew安装, 如果之前用brew安装的go, 可直接brew update go, 否则, 安装go新版: 执行一下 export PATH=$PATH: ...

  9. 为什么代理属性设置成assign为了防止生成保留环来

    循环引用 全部的引用计数系统, 都存在循环应用的问题, 比如以下的引用关系: 1. 对象a创建并引用到了对象b 2. 对象b创建并引用到了对象c 3. 对象c创建并引用到了对象b 这时候b和c的引用计 ...

  10. opengl中VAO,VBO,IBO用法小结【转】

    http://cowboy.1988.blog.163.com/blog/static/751057982014380251300/ opengl中VAO,VBO,IBO用法小结 这三个玩意全面取代旧 ...