Interview Questions

  • View all tutorials
  • blank
  • 3 common JavaScript closure questions
    A lecturer at Hack Reactor made this comment on Quora in response to a question about preparing for the Hack Reactor admission's challenge:
    One big thing that will help you: get intimately familiar with the concepts of recursion and JavaScript closures ... they will come up early in your interactions with Hack Reactor (and are just great things to understand in general).
    Below we'll cover some common questions dealing with closures. In another post we'll cover some recursion questions with solutions.

    Sources

    https://www.quora.com/How-did-you-prepare-for-Hack-Reactors-admissions-challenge

    Questions

    1What will the following code output?
    for (var i = 0; i < 3; i++) {
      setTimeout(function() { alert(i); }, 1000 + i);
    }
    Answer

    The goal of the code above is to alert the numbers 0, 1, and 2 each after 1, 1.1, and 1.2 seconds, respectively. The problem though, is that if you run the above code in your console, you actually get the number 3 alerted 3 times after 1, 1.1, and 1.2 seconds. This is because of an issue with JavaScript closures. Click here to run the above code and see the output for yourself. A JavaScript closure is when an inner function has access to its outer enclosing function's variables and properties. In the code above, the following line of code:

    setTimeout(function() { alert(i); }, 1000 + i);

    uses a variable i which is declared outside of itself. The variable i is actually declared within the for loop and the inner function accesses it. So when the for loop is done running, each of the inner functions refers to the same variable i, which at the end of the loop is equal to 3. Our goal is for each inner function to maintain its reference to the variable i without the value of it being altered. We'll solve this using an IIFE, or an immediately-invoked function expression.

    for (var i = 0; i < 3; i++) {
      setTimeout(function(i_local) { 
        return function() { alert(i_local); } 
      }(i), 1000 + i);
    }

    We pass the variable i into the outer function as a local variable named i_local, where we then return a function that will alert the i_local for us. This should now correctly alert the numbers 0, 1, and 2 in the correct order. Click here to run this new code.

    2Write a function that would allow you to do this.
    var addSix = createBase(6);
    addSix(10); // returns 16
    addSix(21); // returns 27
    
    Answer

    You can create a closure to keep the value passed to the function createBase even after the inner function is returned. The inner function that is being returned is created within an outer function, making it a closure, and it has access to the variables within the outer function, in this case the variable baseNumber.

    function createBase(baseNumber) {
      return function(N) {
        // we are referencing baseNumber here even though it was declared
        // outside of this function. Closures allow us to do this in JavaScript
        return baseNumber + N;
      }
    }
    
    var addSix = createBase(6);
    addSix(10);
    addSix(21);
    3How would you use a closure to create a private counter?
    Answer

    You can create a function within an outer function (a closure) that allows you to update a private variable but the variable wouldn't be accessible from outside the function without the use of a helper function.

    function counter() {
      var _counter = 0;
      // return an object with several functions that allow you
      // to modify the private _counter variable
      return {
        add: function(increment) { _counter += increment; },
        retrieve: function() { return 'The counter is currently at: ' + _counter; }
      }
    }
    
    // error if we try to access the private variable like below
    // _counter;
    
    // usage of our counter function
    var c = counter();
    c.add(5); 
    c.add(9); 
    
    // now we can access the private variable in the following way
    c.retrieve(); // => The counter is currently at: 14
    mrdaniel published this on 12/6/15 | javascript, bootcamp, closure, Hack Reactor
    Comments
  • +
  • 12
  • -
  • Hello mrdaniel!! I am still confused about the first example. The output of the original code is 3s after 1 1.1 1.2 seconds. The confusion is the reference to i. The alert uses i which gives out 3 but the delay (1000+i) uses the immediate i? why is the delay using the instanteous i from the loop but the alert uses the last i in the loop? Did the IIFE use a closure that stored a local value so the i from loop cannot interfere? any help would be greatly appreciated.
  • +
  • 9
  • -
  • Hello txafter, setTimeout is a higher order function (i.e. a function that takes one or more functions as parameters - these function(s) passed as parameters are also known as callbacks). setTimeout has two arguments: the first argument is the function to be invoked (in this case the anonymous function with the alert call), and the second argument is a time interval in milliseconds. setTimeout's job, when called, is to immediately set a timer that will expire after a specified time interval (the second argument to setTimeout). When that timer expires, the code that is in the callback function of the first argument passed to setTimeout is executed (and when this callback function is executed, that's where the interesting effects of JS closures come in...but correct me if I'm wrong, it seems like you have a good handle on that part). setTimeout does not wait for the time interval to expire and then execute. setTimeout executes immediately. It is the callback function in setTimeout's first argument that waits/executes. Let me know if this explanation makes sense.
  • +
  • 8
  • -
  • For question 1, why doesn't the second argument for setTimeout 1000 + i yield 1.001 sec? if 1000 msec = 1 sec, then 1100 is 1.1 sec, right?
  • +
  • 8
  • -
  • Why do you need the inner - inner function to be the IIFE? What is wrong with making the anonymous function in setTimeout as an Immediately Invoked Function Expression, like so (sorry if my formatting is off) :
    for (var i = 0; i < 3; i++) {
      setTimeout(function(j) { 
      	return alert(j); 
        }(i), 1000 + i);
    }
    
    Seems to work fine without the extra function. What am I missing?
  • +
  • 3
  • -
  • Hi! I wrote the following code for question 3. My code looks almost identical to the anwer given above. But when I ran it, only the last input value into the counter is registered. I'm not sure what went wrong. Any insights?
    var counter=function() {
      var _counter=0;
      return {
        add: function(num) { _counter=+num; },
        retrieve: function() { return "the value of counter is currently: "+_counter; }
      };	
    };
    
    var count=counter();
    count.add(9);
    count.add(5);
    count.retrieve(); //==> 'the value of counter is currently: 5'
    
  • +
  • 1
  • -
  • @natashache, in your add function you need to write:
    _counter += num
    not =+ That should fix it :)
    Login to submit a comment