JS编程中我们可能会遇到命名冲突的问题。命名冲突分两种情况来处理,对于模块内部,我们通常创建命名空间来解决;对于不同框架类库,我们采用无冲突处理(多库共存)的手段解决。
1.模块内部,注册命名空间
一个大模块可以细分成若干小模块,命名空间其实就是在大模块的作用域里面声明小的作用域,这样不同作用域之间同名标识符互不影响。
1)用立即执行函数表达式(IIFE)作为作用域。
var a = 1; (function() { var a = 2; console.log(a);//2 })(); console.log(a);//1
IIFE内部想调用外部的同名变量,可以将外部同名变量当参数传进去,但是外部想调用IIFE作用域里的变量却不方便了。
2)对象字面量方式创建命名空间。
对象字面量{}括起来的就是一个作用域,我们通常声明一个对象字面量,然后用“.”的方式给它创建若干属性正是这种原理。
var Lxt = { A : {}, B : {} }; Lxt.A.a = 1; Lxt.B.a = 2; console.log(Lxt.A.a);//1 console.log(Lxt.B.a);//2
A作用域里的a与B作用域里的a互不干扰,这就是对象字面量方式创建命名空间。
3)使用注册函数创建命名空间。
注册函数是上面那种方式的加强版,上面那个例子如果没事先定义A和B,则下面的Lxt.A.a会报错,注册函数其实就是将定义空间的过程封装了起来。
var Lxt = {}; var namespace = function(scope, space) { var spaces = space.split("."); var currentScope = scope; for(var i = 0, len = spaces.length; i < len; i++) { if(!currentScope[spaces[i]]) { currentScope[spaces[i]] = {}; } currentScope = currentScope[spaces[i]]; } }; namespace(Lxt, "A"); namespace(Lxt, "B");
得到的结果同2)中声明的Lxt一样。
2.不同类库无冲突处理
无冲突处理的原理很简单,类库加载前保存冲突命名,类库加载后再将冲突命名重新赋值回去。
拿“$”来举例,我在$1.js中声明一个全局变量“$”,在$2.js中也声明一个全局变量“$”,先加载$1,之后马上加载$2,调用时“$”则不会指向$1的$内容了。
//$1.js: var $ = J = { test : function() { return "from $1.js..."; } };
//$2.js: var $ = K = { test : function() { return "from $2.js..."; } };
页面先后引入$1.js与$2.js后测试发现,访问不了$1的test函数了。
console.log($.test());//from $2.js...
那么无冲突怎么处理呢?拿$2来举例,在$2代码最前面保存“$”,这时,变量保存了$1的内容,模仿JQuery的noConflict函数,调用该函数的时候将保存的变量重新赋给“$”。最终效果是“$”指向“$1”的内容。
//$2.js var _$ = window.$; var $ = K = { test : function() { return "from $2.js..."; }, noConflict : function() { window.$ = _$; return K; } };
测试结果如下:
$.noConflict(); console.log($.test());//from $1.js...