|
 |
栏目导栏 |
|
| |
|
|
|
|
 |
资料搜索 |
|
| |
|
|
|
|
 |
热门文章 |
|
| |
|
|
|
|
 |
最新文章 |
|
| |
|
|
|
| |
| |
|
|
|
| |
| Ajax-JavaScript-namespace |
|
引入Namespace的目的 RKpLinux联盟 JavaScript中引入Namespace和C#一样,都是为了避免命名冲突。但是Js又有些特殊: RKpLinux联盟 RKpLinux联盟 js解释执行,如果后面定义了同名的变量会覆盖前面变量,并用应用新定义变量的语义。这在Js中合法,没有错误提示,因此bug很难找。 RKpLinux联盟 RKpLinux联盟 可以想象,我调用了一个第三方模块,如果这个模块没有定义在Namespace中,我定义的变量和函数很可能就覆盖了第三方的同名符号。 RKpLinux联盟 RKpLinux联盟 模块原则 RKpLinux联盟 RKpLinux联盟 a module should never add more than a single symbol to the global namespace。 RKpLinux联盟 RKpLinux联盟 只有这样才能保证模块的重用性,MicrosoftAJax就是这样实现的。除了几个以$开头的全局符号,其余符号都定义在Sys命名空间中。 RKpLinux联盟 RKpLinux联盟 $符号 RKpLinux联盟 RKpLinux联盟 MA.js,部分违反了上面的原则,但是它对违反原则的变量命名都以$开头。这样也对模块的调用者有个约定,即:$开头的变量属于全局名称空间,调用者如果也以$命名变量必须自觉保证没有冲突。可以看到Animaions.js有类似用法。 RKpLinux联盟 RKpLinux联盟 类似的约定还有:以_开头的变量为私有,不应该调用。他们的实现可能会变化,调用者如果应用,必须做层封装。 RKpLinux联盟 RKpLinux联盟 Namespace通常实现 RKpLinux联盟 对于JS这种动态语言来说,实现namespace很简单,定义一个对象变量即可。 RKpLinux联盟 RKpLinux联盟 如: RKpLinux联盟 RKpLinux联盟 var Sys={}; RKpLinux联盟 RKpLinux联盟 Sys.Debug={trace:'trace',fail:'fail'}; RKpLinux联盟 RKpLinux联盟 Sys.StringBuilder={}; RKpLinux联盟 RKpLinux联盟 document.write(Sys.Debug.fail); RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 定义了Sys名称空间,在其中定义了Debug,StringBuilder对象。 RKpLinux联盟 RKpLinux联盟 上面的定义过于简单,实际上还要做一下检测,看看是否已经定义过相同的名称空间,如果有跑出异常或者用已经存在的名称空间;是否namespace是对象,不是也抛异常。 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 var Sys= undefined; RKpLinux联盟 RKpLinux联盟 if(!Sys) Sys={}; RKpLinux联盟 RKpLinux联盟 else if(typeof Sys!=object) RKpLinux联盟 RKpLinux联盟 throw new Error('类型错误'); RKpLinux联盟 RKpLinux联盟 Sys.Debug={trace:'trace',fail:'fail'}; RKpLinux联盟 RKpLinux联盟 Sys.StringBuilder={}; RKpLinux联盟 RKpLinux联盟 document.write(Sys.Debug.fail) RKpLinux联盟 RKpLinux联盟 上面是比较严格的实现,MicrosoftAjax.js,就是用上面的逻辑,只是他代码更复杂些。 RKpLinux联盟 RKpLinux联盟 注:在Antechinus中如果不指定undefined,会出错。但是Js语法没有这种要求。猜测Antechinus可能会先读取Sys,读没有声明的变量会有异常。 RKpLinux联盟 RKpLinux联盟 MicrosoftAjax.js实现 RKpLinux联盟 MA中注册Namespace,通过循环的方式,window对象保持对rootNamespace的引用,rootNamespace又引用子空间。形成一条链。 RKpLinux联盟 RKpLinux联盟 如注册:Type.registerNamespace('My.I.M'); RKpLinux联盟 RKpLinux联盟 会注册下面三个空间:My,My.I,My.I.M。其中My是rootNamespace。My,My.I被隐含注册,可以直接使用。 RKpLinux联盟 RKpLinux联盟 MA的实现看起来很复杂,但是只要注意下面几条还是很容易看懂的: RKpLinux联盟 RKpLinux联盟 利用window RKpLinux联盟 RKpLinux联盟 var rootObject = window; RKpLinux联盟 RKpLinux联盟 在第一次循环中rootObject一直指向window,如果根没有被注册则在window中注册根命名空间。结果是:window[‘My’]={},window===rootObject。 RKpLinux联盟 RKpLinux联盟 第二次循环,winodw指向rootObject[‘My’]。以My为根,注册I。结果:window[‘My’][‘I’]={},window===rootObject[‘My’]。 RKpLinux联盟 RKpLinux联盟 第三次注册My.I.M。 RKpLinux联盟 RKpLinux联盟 因为用到了window,RegisterNamespace也失去了通用性。 RKpLinux联盟 RKpLinux联盟 Eval RKpLinux联盟 RKpLinux联盟 值支持primitive value RKpLinux联盟 RKpLinux联盟 eval(code) RKpLinux联盟 RKpLinux联盟 code RKpLinux联盟 RKpLinux联盟 A string that contains the JavaScript expression to be evaluated or the statements to be executed. RKpLinux联盟 RKpLinux联盟 Returns RKpLinux联盟 RKpLinux联盟 The value of the evaluated code, if any. RKpLinux联盟 RKpLinux联盟 类似数组的语法访问对象 RKpLinux联盟 RKpLinux联盟 如winodw[‘Sys’][‘Net’] RKpLinux联盟 RKpLinux联盟 代码: RKpLinux联盟 RKpLinux联盟 Type.registerNamespace = function Type$registerNamespace(namespacePath) { RKpLinux联盟 RKpLinux联盟 /// <param name="namespacePath" type="String"></param> RKpLinux联盟 RKpLinux联盟 var e = Function._validateParams(arguments, [ RKpLinux联盟 RKpLinux联盟 {name: "namespacePath", type: String} RKpLinux联盟 RKpLinux联盟 ]); RKpLinux联盟 RKpLinux联盟 if (e) throw e; RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 if (!Type.__fullyQualifiedIdentifierRegExp.test(namespacePath)) throw Error.argument('namespacePath', Sys.Res.invalidNameSpace); RKpLinux联盟 RKpLinux联盟 var rootObject = window; RKpLinux联盟 RKpLinux联盟 var namespaceParts = namespacePath.split('.'); RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 for (var i = 0; i < namespaceParts.length; i++) { RKpLinux联盟 RKpLinux联盟 var currentPart = namespaceParts[i]; RKpLinux联盟 RKpLinux联盟 var ns = rootObject[currentPart]; RKpLinux联盟 RKpLinux联盟 if (ns && !ns.__namespace) { RKpLinux联盟 RKpLinux联盟 throw Error.invalidOperation(String.format(Sys.Res.namespaceContainsObject, namespaceParts.splice(0, i + 1).join('.'))); RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 if (!ns) { RKpLinux联盟 RKpLinux联盟 ns = rootObject[currentPart] = {}; RKpLinux联盟 RKpLinux联盟 if (i === 0) { RKpLinux联盟 RKpLinux联盟 window.__rootNamespaces[window.__rootNamespaces.length] = ns; RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 ns.__namespace = true; RKpLinux联盟 RKpLinux联盟 ns.__typeName = namespaceParts.slice(0, i + 1).join('.'); RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 RKpLinux联盟 var parsedName; RKpLinux联盟 RKpLinux联盟 try { RKpLinux联盟 RKpLinux联盟 parsedName = eval(ns.__typeName); RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 catch(e) { RKpLinux联盟 RKpLinux联盟 parsedName = null; RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 if (parsedName !== ns) { RKpLinux联盟 RKpLinux联盟 delete rootObject[currentPart]; RKpLinux联盟 RKpLinux联盟 throw Error.argument('namespacePath', Sys.Res.invalidNameSpace); RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 ns.getName = function ns$getName() {return this.__typeName;} RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 rootObject = ns; RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟 RKpLinux联盟 } RKpLinux联盟
Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论 |
|
|
|
|
|