iank
iank

Reputation: 13

Trouble understanding Javascript nested function/closure

I'm attempting to port the following JavaScript code to ruby: https://github.com/iguigova/snippets_js/blob/master/pokerIn4Hours/pokerIn4Hours.js

I think I have most of it sorted, the function that is giving me grief is:

var kickers = function(idx){ // http://en.wikipedia.org/wiki/Kicker_(poker)        
    idx = idx || -15; 
    var notplayed = Math.max(input.length - 1/*player input*/ - 5, 0);
    return function(all, cardinality, rank) {
        return (all || 0) + (((cardinality == 1) && (notplayed-- <= 0)) ? rank * Math.pow(10, ++idx) : 0);
    };
}();

And it is called further down like so:

k = kickers(k, cardsofrank[i], i);

I was wondering if someone could explain how this works in JavaScript. The fact that the inner function has 3 parameters and the outer only has 1 is confusing, especially given that it is called with 3 parameters. I would like to understand what it's trying to accomplish, so that I can port the code with confidence.

Upvotes: 0

Views: 44

Answers (2)

Amitesh
Amitesh

Reputation: 1517

var kickers = function(idx){
    var xyz;//below function in return statement can access this and argument idx
    return function(...) {//this ensures that your kickers is infact a function
    };
}();//invoke this function instantly due to () and assign the output to kickers

When Javascript interpreter read above assignment to Kickers it will execute the anonymous function Since that function itself returns a function, the kickers will now a function (with closure). Meaning the kickers function will have a reference to the environment variables (idx and notplayed )

Edit:
1) Where it is getting value of idx - Since nothing is passed while invoking the function(last line ();) the idx will be undefined and idx = idx || -15; will assign the value -15 to it.

2) Could this be re-written without an inner function? - Yes. But the current implementation has an advantage where the scope of idx and notplayed is limited to kicker function and will not be accessible globally. Here is how you can write it directly as a function

/* now  idx and notplayed is global- but its meant to be used only by kicker
 * we cant move it inside the function definition as it will behave as local variable to the function 
 * and hence will be freed up once executed and you cannot maintain the state of idx and notplayed
*/
var idx = -15;
var notplayed = Math.max(input.length - 1/*player input*/ - 5, 0);
var kickers = function(all, cardinality, rank) {            
    return(all || 0) + (((cardinality == 1) && (notplayed-- <= 0)) ? rank * Math.pow(10, ++idx) : 0);
}

Upvotes: 0

Prabhu Murthy
Prabhu Murthy

Reputation: 9261

function(idx) this function returns a new function function(all, cardinality, rank) and this new function is referred by kickers variable in turn. so kickers is basically pointing at the inner function you have returned.

the only way to call your returned function is this kickers(k, cardsofrank[i], i)

Upvotes: 1

Related Questions