Jamie Hutber
Jamie Hutber

Reputation: 28096

Closure Conditional - How does this returning function get the value set as a parameter when its not passed as a parameter?

So, return function (n) still returns the value that was initially given to its parent function as an augment. But i don't get why, when i haven't passed n's value from var digit_name = (function(){ does return function(n){ get its value from the original argument.

Especially as I have overwritten it with var n = 4;

JS

   var digit_name = (function(){
       var names;
       var n = 4;
       return function(n){
           if(!names){
               names = ['zero','one','two','three'];
           }
       return names[n];
       }
   }());
   console.info(digit_name(3)); //Three

Also if I overwrite return function(n) with a number return function(1) I will SyntaxError: missing formal parameter. I understand that return names[n] wouldn't then know what n, so why not give a n is undefined error?

Upvotes: 1

Views: 219

Answers (3)

Corey
Corey

Reputation: 5818

In your example, you have a naming and scope collision with the variable n. The defined var n in the outer function is assigned a value of 4. Your inner function accepts a single parameter declared as n. So, the n variable in your inner function is referring to its' internal scope and no longer refers to var n in the outer function. If you want a default value, you can name the outer variable something different and check for an existence of the value n in your inner function:

var digit_name = (function () {
    var names;
    var defaultn = 0;
    return function (n) {
        if (!n) n = defaultn;
        if (!names) {
            names = ['zero', 'one', 'two', 'three'];
        }
        return names[n];
    }
}());
console.info(digit_name(3)); //Three
console.info(digit_name()); //zero

Upvotes: 1

James Allardice
James Allardice

Reputation: 166021

I'm not entirely sure what you're asking, so I'm just going to explain why you get the output you do...

When the code runs, the IIFE (immediately invoked function expression) is executed and digit_name refers to the function returned from it. That function still has access to the outer n and names variables via a closure.

You then invoke digit_name and pass it an argument. The formal parameter of digit_name is n, which shadows the n declared in the outer scope. There is no longer any way you can refer to that outer n. So whatever value you pass into digit_name will be used.

Effectively, the IIFE in this case is pointless (apart from the fact that it prevents you from having to create the array every time the function is invoked) and your code is equivalent to this except for that array difference:

var digit_name = function (n) {
    return ['zero','one','two','three'][n];
};
console.info(digit_name(3)); // "three"

Upvotes: 2

Justin Bicknell
Justin Bicknell

Reputation: 4808

If you look at the definition of digit_name in the console you will see it is this function:

   function (n){
       if(!names){
           names = ['zero','one','two','three'];
       }
       return names[n];
   }

So you haven't overwritten n, since the scope of n within this function is now the parameter n, not the variable declared above.

Upvotes: 1

Related Questions