最近写代码时碰到一个诡异的问题,那就是匿名函数作为函数参数的问题。上代码:
var fnCacheArr=[];
function pushArrFn(parFn){
/*
处理其他逻辑,假设这段代码很长很复杂
*/
fnCacheArr.push(parFn);
parFn();
/*
处理其他逻辑,假设这段代码很长很复杂
*/
}
function myTest(name){
var count=0;
for(var i=0;i<10;i++){
count=count+5;
(function(i){
pushArrFn(function(){
/*
处理其他逻辑,假设这段代码很长很复杂
*/
console.log(i,count,name);
/*
处理其他逻辑,假设这段代码很长很复杂
*/
});
})(i);
}
}
myTest('muma');
console.log(fnCacheArr[0]==fnCacheArr[1]);//结果为false,说明有两个匿名副本,性能低下,浪费资源
这段代码能正常运行,结果为:
myTest执行时,for循环不停地执行pushArrFn方法,作为pushArrFn参数的匿名函数就会不停的生成新的函数对象来运行,性能低下。fnCacheArr[0]和fnCacheArr[1]不相等,也说明了匿名函数在内存中生成了不同的副本,而不是同一副本。如果该匿名函数每次运行完就释放资源还好,但是像我代码里面的,有个fnCacheArr数组存储这些不停新生成的函数对象副本的话,性能问题就更加明显了。
那么解决方案是什么呢?
我想到的方法就是将作为函数参数的匿名函数提取出来,再作为pushArrFn的参数。
这样提取代码,是解决了我上面的问题,但是又有新问题了。
那就是原来代码里面能正常访问到的变量访问不到了。我只好将
console.log(i,count,name);
这句代码注释掉,如果不注释掉,运行结果是这样的:
原来可以正常访问的变量,现在访问不到了,怎么办?
其实问题很简单,假如A函数的参数是匿名函数B。
如果这个A函数被多次调用,匿名函数B就会反复生成函数对象,甚至反复生成的函数对象副本不能立即释放资源(比如我上面用数组一个一个存起来),如果将匿名函数提取出来,上述问题就解决了。
如果匿名函数B需要访问当前上下文环境的变量,这时就无法提取出来了,提取出来的函数将面临很多变量访问不到的问题。
这个问题对我来说好棘手呀,心烦,求js大神解答指导。
迷茫2017-04-10 17:08:33
(function(i){
pushArrFn(function(){
/*
处理其他逻辑,假设这段代码很长很复杂
*/
console.log(i,count,name);
/*
处理其他逻辑,假设这段代码很长很复杂
*/
});
})(i);
pushArrFn 里的要加上 上下文环境中的变量,那么 传入的那个 function 就是大家所说的闭包咯;
那么 console.log(fnCacheArr[0]==fnCacheArr[1]);//结果为false
就很正常了;
甚至反复生成的函数对象副本不能立即释放资源(比如我上面用数组一个一个存起来)
如果没有对这些闭包的引用,那么垃圾回收器,后面是可以回收这些资源的;
如果匿名函数B需要访问当前上下文环境的变量,这时就无法提取出来了,提取出来的函数将面临很多变量访问不到的问题。
建议你看下 作用域链的概念,就可以理解为什么在外面获取不到 i,count,name 了,因为javascript是静态作用域;
好奇, fnCacheArr 的目的是什么?
阿神2017-04-10 17:08:33
参数提取出来不就行了, 一直传递到被调用的地方
function pushArrFn(parFn, i) {
fnCacheArr.push(parFn);
parFn(i);
}
function paramFn(i) {
console.log(i + "hahaha");
}
function myTest(name) {
var count=0;
for(var i=0;i<10;i++) {
count=count+5;
// (function(i){
// pushArrFn(paramFn, i);
// })(i);
pushArrFn(paramFn, i);
}
}