javascript 模拟函数指针
来源:uedmagazine 时间:2009-09-19 18:02:00
这个是今年年初写的一篇,拿出来温习下。
指针让程序结构变得混乱,也让程序执行效率提高,因此在oo的语言中不提倡指针的使用,使得程序结构清晰易读可维护,特别是在工程中,降低了人员流动带来的代码维护成本。在java和js中甚至将指针完全禁止,只提供引用。但指针毕竟是引用的基础,指针使用恰当也会提高程序的效率,像我这种之前一直生活在 c和c++中,转型到js之后没有指针的编码风格总有些不习惯,这也让我在设计js的逻辑的时候经常卡壳,并深深怀念当年在指针的海洋中飘来飘去的感觉。
语言有语言的优势,也有它的劣势,语言也总是用hack的方法来弥补劣势,c中的goto和js中的eval都是这种例子。js的优点是语义丰富逻辑清晰语法灵活多变,函数操作是最基础的操作,但有时会遇到很多困惑,比如函数交换:
现在有两个函数:
var fun1 = function(str){
alert('执行函数1,参数:'+str);
};
var fun2 = function(str){
alert('执行函数2,参数'+str);
};
交还这两个函数,最简单的方法是:
var _o=fun1;
fun1=fun2;
fun2=_o;
能否将函数交换操作封装到函数中呢?比如:
var changefun = function(fun1,fun2){
var _o=fun1;
fun1=fun2;
fun2=_o;
};
最简单的想法是将fun1和fun2的指针传递到changefun中,让changefun完成函数指针的交换,在js中这是不可能的,js没有指针,而且传递到changefun中的函数都会被闭包起来,脱离原有的命名空间。但我可以这样:
var changefun = function(s1,s2){
eval('var _o = '+s1+';'+s1+' = '+s2+';'+s2+' = _o;');
};
传递函数名给changefun,在changefun中构造交换的代码再执行,虽然changefun里的变量都被闭包住,但是参数是函数名是字符串,这样changefun中构造好的代码中的s1和s2却可以伸展到以外的命名空间,只要在changefun同一级的命名空间中存在fun1和fun2,代码就会被正确执行。比如这样一段代码就会被正确执行:
var fun1 = function(str){
alert('执行函数1,参数:'+str);
};
var fun2 = function(str){
alert('执行函数2,参数'+str);
};
var changefun = function(s1,s2){
eval('var _o = '+s1+';'+s1+' = '+s2+';'+s2+' = _o;');
};
changefun('fun2','fun1');
fun1('1');
fun2('2');
但是changefun不总是和被交换的函数在同一个命名空间中,例如这样一段代码就不会交换成功:
var changefun = function(s1,s2){
eval('var _o = '+s1+';'+s1+' = '+s2+';'+s2+' = _o;');
};
var myClass1 = function(){
var fun1 = function(str){
alert('执行函数1,参数:'+str);
};
var fun2 = function(str){
alert('执行函数2,参数'+str);
};
return {
init:function(){
changefun('fun2','fun1');
},
fun1:fun1,
fun2:fun2
};
};
var a = new myClass1();
a.init();
a.fun1('1');
a.fun2('2');
对于这种情况,则必须把changefun放到与fun1和fun2同一个根空间下,这样函数交换成功:
var changefun = function(s1,s2){
eval('var _o = '+s1+';'+s1+' = '+s2+';'+s2+' = _o;');
};
var myClass1 = function(){
var fun1 = function(str){
alert('执行函数1,参数:'+str);
};
var fun2 = function(str){
alert('执行函数2,参数'+str);
};
return {
init:function(){
changefun('fun2','fun1');
},
fun1:fun1,
fun2:fun2
};
};
var a = new myClass1();
changefun('a.fun1','a.fun2');
a.fun1('1');
a.fun2('2');