2012-11-18 132 views
4

我有一个函数f可以用任意参数调用。当它被2个参数调用时,它执行一个操作。当它被调用> 2个参数时,它必须本身折叠其他。也就是说,当我们调用f(a,b,c,d)时,函数应重新排列为f(f(f(a,b),c,d)。我需要这个尽可能优化。我带着2个解决方案和基准测试他们:折叠函数参数的最佳方式是什么?

alphabet = 'abcdefhijklmnopqrstuvwxyz'.split(''); 
var last_mark; 
benchmark = function(msg){ 
    alert(msg.replace('$TIMEDIFF',Date.now()-last_mark)); 
    last_mark=Date.now(); 
}; 
fa = function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z){ 
    if (c) return fa(fa(a,b),c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z); 
    return a+b; 
}; 
fb = function(a,b,rest){ 
    if (rest) return fb.apply(this,[fb(a,b)].concat(Array.prototype.slice.call(arguments,2))); 
    return a+b; 
}; 
benchmark("Starting benchmark:"); 
for (var i=0; i<100000; ++i) fa.apply(this,alphabet); 
benchmark("Function 1: $TIMEDIFF"); 
for (var i=0; i<100000; ++i) fb.apply(this,alphabet); 
benchmark("Function 2: $TIMEDIFF"); 

第一个解决方案是快(node.js的上200毫秒VS 4000ms)。这可以进一步优化吗?

+2

大概是对http://codereview.stackexchange.com/更适合。 –

+0

谢谢。有些有趣的堆栈交换我不知道。 – MaiaVictor

+0

@Cam你是什么意思? – MaiaVictor

回答

1

像这样的事情会降低阵列创建和操纵

fa = function(a,b){ 
    function recursive(a, b, rest) { 
     if (rest && rest.length) 
      return recursive(recursive(a,b), rest.pop(), rest); 
     return a+b; 
    } 
    return recursive(a, b, Array.prototype.slice.call(arguments, 2).reverse()); 
}; 

或者这样切的函数调用的次数减半:

fa = function(a,b) { 
    function recursive(a, b, rest) { 
     var result = a + b; 
     return rest.length ? recursive(result, rest.pop(), rest) : result; 
    } 
    return recursive(a, b, Array.prototype.slice.call(arguments, 2).reverse()); 
}; 

我假设成本的.reverse()值得使用.pop()而不是.shift()。你可能想尝试两种方式。


当然,你可以重复使用的功能,以及:

fa = (function() { 
    function recursive(a, b, rest) { 
     var result = a + b; 
     return rest.length ? recursive(result, rest.pop(), rest) : result; 
    } 
    return function(a,b) { 
     return recursive(a, b, Array.prototype.slice.call(arguments, 2).reverse()); 
    }; 
})(); 
1

你为什么不使用对象作为参数?

var o = { 
    a:value1, 
    b:value2, 
    ... 
    z:value26 
}; 

fa(o); 

function fa(obj){ 
    if(obj.c){ // or any other logic 
    return fa(obj); 
    } 
    return o; 
} 

或全局变量(不带参数)

fa(); 

function fa(){ 
    if(o.c){ // or any other logic 
    o.c = o.d + o.e; 
    fa(); 
    } 
} 
1

最快的方式似乎与迭代来代替递归。

定义高阶函数folder

var folder = function(func) { 
    return function() { 
      var args = Array.prototype.slice.call(arguments), len = args.length, result = args[0], i = 1; 
      for(; i < len; i++){ 
       result = func.call(this, result, args[i]); 
      } 

      return result; 
    }; 
}; 

检查这个PERF的测试:http://jsperf.com/varargs-fold

2

ES5引入了.reduce()功能,准确的任务。它为前两项调用一些函数,然后再次调用它传递第一个调用和第三个项目的返回值,然后再次调用它,传递返回值,即调用和第四个项目,依此类推。

var f = function() { 
    return toArray(arguments).reduce(function (a, b) { 
     return a + b;  
    }); 
}; 

现场演示:http://jsfiddle.net/hpAtB/1/

+0

对于ES5减少+1。 –

+0

我喜欢使用减少。不知道为什么我没有想到要使用它。 FWIW,我将你的代码添加到了这个测试中。 FF有点慢,但在Chrome中表现非常好。 http://jsperf.com/varargs-fold/4 –

相关问题