What is the best way to bend function arguments?

I have a function f that can be called with arbitrary arguments. When it is called with two arguments, it performs the operation. When it is called by s> 2 arguments, it must dump the rest. That is, when we call f(a,b,c,d) , the function should be rebuilt as f(f(f(a,b),c,d) . I need this to be as optimized as possible. I supply 2 solutions and compare them:

 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"); 

The first solution was faster (200 ms versus 4000 ms on node.js). Could this be optimized even further?

+4
source share
4 answers

The .reduce .reduce() function was introduced in .reduce() for this exact task. It calls some function for the first two elements, then calls it again, passing the return value of the first call and the third element, then calls it again, passing the return value of this call, and the fourth element, etc.

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

Live demo: http://jsfiddle.net/hpAtB/1/

+2
source

Something like this will reduce the creation and manipulation of the array.

 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()); }; 

Or, like this, cut the number of function calls in half:

 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()); }; 

I assume that the cost of .reverse() worth increasing the use of .pop() instead of .shift() . You might want to try both ways.


Of course, you can also reuse this function:

 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
source

Why aren't you using an object as an argument?

 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; } 

or global variable (no arguments)

 fa(); function fa(){ if(oc){ // or any other logic oc = od + oe; fa(); } } 
+1
source

The fastest way replaces recursion with an iteration.

Define a higher order function 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; }; }; 

Check out this perfection test: http://jsperf.com/varargs-fold

+1
source

Source: https://habr.com/ru/post/1446812/


All Articles