总所周知,Javascript是没有所谓命名空间、包、类、私有成员、公有成员等的概念的,好像让我们感到亲切的只有对象(object)。这是对象, 那是对象,连函数也是对象,我要疯了!!但这不影响它成为一门优秀的语言,不影响基于它实现强大的功能,也不影响建立大量提高开发效率的框架,甚至JS已 被作为服务器端语言实现(NodeJS)。
为了统一命名前缀,减少命名冲突,为了减少出现大量并列的全局函数,命名空间还是挺有用的方法,它可以在JS中较真实模拟C# namespace。
有的时候,我们可能会定义大量具有层级关系的对象(功能)集合,例如:LOTTERY.SSQ.HARD.=function(){} ....。可能包括很多方法、对象,也可能包含很深的层级,这时候命名空间是最好的管理方法之一。
一个好的JS命名空间至少应该包括:
这样,我们就可以很方便的注册我们需要的对象IWAYNE.namespace(" LOTTERY.SSQ.HARD ")。当然,我们可以增加第二个参数,以传入回调函数,以达到一步注册的目的。
1 var IWAYNE= IWAYNE || {}; 2 IWAYNE.namespace = function (ns_string) { 3 var parts = ns_string.split('.'), 4 parent = IWAYNE, 5 i; 6 //取得namespace名称 7 if (parts[0] === "IWAYNE") { 8 parts = parts.slice(1); 9 } 10 for (i = 0; i < parts.length; i += 1) { 11 // 创建不存在的模块 12 if (typeof parent[parts[i]] === "undefined") { 13 parent[parts[i]] = {}; 14 } 15 parent = parent[parts[i]]; 16 } 17 return parent; 18 };
二、构件化(Component)
软件开发的最高境界是最具有良好的软件体系结构和大量封装精细的构件库(组件库),这时候框架将是快速搭建软件的最好模式之一。同样的思想,在前端也不断 得到体现,涌现出大量诸如JQUERY、YUI等优秀的框架。虽然没有像C#、JAVA那样丰富的语法结构,但通过运用一定技巧一样可以建立具备良好接 口、功能独立,封装完善并且易于增删改查的前端构件,甚至建立以构件为基础的框架。
闭包机制为我们提供了非常好的实现方式,代码如下:
当然,这里可以使用namespa组织结构,也可以将公共接口改为function,以达到复用的目的。如果我们需要的是一个包含各种方法集合的对象,且 只有一个,那么上面的代码是可行的;如果需求需要大量参数不同的实例,那么返回function是一个不错的选择。
最后,闭包也是可以传递变量的,如果你将IWAYNE(名称可变)和window作为对象传入,那么一个简易的框架就诞生了。
1 var LOTTERY_TOPIC = LOTTERY_TOPIC || {}; 2 LOTTERY_TOPIC.SSQ = (function () { 3 // 私有属性、DOM 4 var red_num = 0, 5 blue_num = 0, 6 hard_num = 0, 7 red_balls = document.getElementById("red"), 8 red_btns = red_balls.getElementsByTagName("span"); 9 // 内部方法 10 checkIsLegal = function(){ 11 .... 12 }, 13 computeBonus = function(r,b,h){ 14 .... 15 }, 16 init = function(){ 17 .... 18 }; 19 // 公共接口 20 return { 21 compute : computeBonus, 22 init : init 23 }; 24 }());
二、“沙箱”(Sandbox)
上述的方法一定程度上是完美的,但由于其构件或框架名称总依赖于全局对象,也就意味着还是会有命名冲突(Collision)的,这样也就无法在使两个版 本框架共存。同时,随着功能扩展,其命名层级也会不断增加,导致解析和记忆困难。相信没有太多人会喜欢A.B.C.D.E.F....这么长的命名。
下面的代码来自YUI的模拟,也是我非常喜欢读YUI代码的原因。它虽然盘根错节,复杂但不失灵活,庞大但不失简单(非广告)。再说该方法,可以很好解决上面提到的问题,提供一个很好的“环境”去保证每个模块或组件的封闭性、互斥性。
1 function Sandbox() { 2 var args = Array.prototype.slice.call(arguments), 3 // 最后的参数的回调 4 callback = args.pop(), 5 // 模块传入数组 6 modules = (args[0] && typeof args[0] === "string") ? args : args[0], 7 i; 8 // 保证构造函数调用 9 if (!(this instanceof Sandbox)) { 10 return new Sandbox(modules, callback); 11 } 12 // 定义属性 13 this.a = 1; 14 this.b = 2; 15 // 绑定模块 16 if (!modules || modules === '*') { 17 modules = []; 18 for (i in Sandbox.modules) { 19 if (Sandbox.modules.hasOwnProperty(i)) { 20 modules.push(i); 21 } 22 } 23 } 24 // 模块初始化 25 for (i = 0; i < modules.length; i += 1) { 26 Sandbox.modules[modules[i]](this); 27 } 28 // 回调 29 callback(this); 30 } 31 // any prototype properties as needed 32 Sandbox.prototype = { 33 name: "IWAYNE", 34 version: "1.0", 35 getName: function () { 36 return this.name; 37 } 38 };
这里仅举了两个模式,其实包括国产框架在内,大量精美的JS代码不断出现,各种模式层出不穷。我感觉Javascript语言就像五线谱,它有简洁、灵活的语法,只要多思考,多读好的代码,相信上帝也会疯狂!