Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it good to make function in function using 'return'?

While I was investigating functions, I realised that I can create embedded functions. Firstly, I thought it may be useful for structuring code. But now I suppose it isn't good style of coding. Am I right? Here is an example.

function show () {
    return function a() {
        alert('a');
        return function b() {
            alert('b');
        }
    }
}

And I can call alert('b') using this string: show()();

In what situations is better to use this method and in what not?

like image 372
Vlad Holubiev Avatar asked Dec 25 '22 17:12

Vlad Holubiev


1 Answers

Yes, this has many uses.

Currying

Firstly, you may want to use currying, where you encapsulate a function with a single argument with a function with many arguments. For example,

function getHandler(num){
 return function(){
  alert(num);
 }
}

myElement.onclick=getHandler(1)
myOtherElement.onclick=getHandler(25)
anotherElement.onclick=getHandler(42)

onclick() cannot be given arbitrary arguments as it is called by the system. Instead of writing 3 different handlers that alert different numbers, this reduces the bloat by creating a function that can generate arbitrary handlers of the "alert a number" type. Of course, this is a rather simplistic example, but if one had to do something considerably more complicated than alert(), the benefits of currying are evident.

Efficiency

Another situation is when you have a complicated function that has one computationally-heavy portion, which is followed by a computationally-light portion. The two portions take different parameters, and usually the parameters for the first portion will be the same. Some variation of memoization can be used to solve this, but function-as-return value works too.

For example, let's say you have a function of the following form:

function doSomething(a,b,c,x,y){
//Do some complicated calculations using a,b,c, the results go to variables e,f,g

//Do some simple calculations using e,f,g,x,y, return result
}

If I want to run doSomething(1,2,3,18,34)+doSomething(1,2,3,55,35)+doSomething(1,2,3,19,12), it would take 3 times the execution time as the long part is execute every time.

However, we can write it as:

function doSomethingCreator(a,b,c){
//Do some complicated calculations using a,b,c, the results go to variables e,f,g
 return function(x,y){
  //Do some simple calculations using e,f,g,x,y, return result
 }
}

Now, all I need to do is call doSomethingCreator() for my set of parameters, and use the created function (which is fast) to get the final results. The code becomes:

var doSomething123=doSomethingCreator(1,2,3);
console.log(doSomething123(18,34)+doSomething123(55,35)+doSomething123(19,12))

One example of this is solving differential equations. Differential equations do not have a single solution if some "boundary conditions" are given. However, (especially for homogenous equations), after one point it is easy to vary the boundary conditions and get solutions. And usually one needs to solve the same equation for different boundary conditions multiple times. So, if you want to write a library method, you would have it take the homogenous equation as the input, and it would return a function, which in turn can be given the boundary conditions as an input to get the final solution.

"Static" variables via closures

Sometimes, you want to be able to easily create a set of variables and carry them around.

For example, if you want to create a counter function:

function generateCounter(){
var c=0;
return function(){
        c++; 
        return c;
       }
}

We can use this to make many independent counters, for example:

myCtr1=generateCounter();
myCtr2=generateCounter();

myCtr1(); //Returns 1
myCtr1(); //Returns 2
myCtr2(); //Returns 1
myCtr1(); //Returns 3
myCtr2(); //Returns 2

Each counter is independent. Of course, in this case, it would be easier to jut use myCtr1=0;myCtr2=0 and then the ++ operator, but what if you want to record the times when they were incremented? Extending the ++ case would involve a lot of code duplication, however, here we can tweak it pretty easily:

function generateCounter(){
var c=[]; // The length of c is the value of the counter
return function(){
        c.push((new Date()).getTime()); 
        return c;
       }
}

When you should not use it

Whenever there is no obvious gain in doing so.

Aside from when you want to use it for closure-bound variables, there usually isn't much point in doing it with 0 arguments for the outer function as the inner function becomes the same function. See if it really improves the program, and then use it.

like image 54
Manishearth Avatar answered Dec 28 '22 07:12

Manishearth