Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When are nested functions generally appropriate in JavaScript?

Tags:

I am learning JavaScript through this website. The link is to the specific chapter that I'm reading right now.

In the book, the author talks about keeping the implementation details of a module on a local scope. He achieves it by doing:

var dayName = function() {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
               "Thursday", "Friday", "Saturday"];
  return function(number) {
    return names[number];
  };
}();

I understand how this works, but I do not understand why he is doing it this way. Why wouldn't he just do...

function dayName(number) {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
               "Thursday", "Friday", "Saturday"];
  return names[number];
}

...which to me looks like a much cleaner and readable code? Given his goal of keeping names within local scope, creating a nested lambda seems redundant.

Is there any real advantage to using the nested function in this case? Or is he using it just for educational purposes?

Thanks!

like image 699
spicypumpkin Avatar asked Mar 31 '17 02:03

spicypumpkin


2 Answers

The toy example you show is not very compelling. The main advantage of writing it that way is that the array is only created once, rather than every time you call the function. This makes it a little faster, at the expense of keeping the array allocated for the entire session (a common time-space tradeoff). In practice, few people program this way.

The technique becomes more useful when you have multiple functions and they operate on shared data. If one of the functions modifies the variable, this is remembered in the closure, and visible to other functions when they're called later.

var dayName = function() {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
               "Thursday", "Friday", "Saturday"];
  return {
    getDay: function(number) {
        return names[number];
    },
    setDay: function(number, newName) {
        names[number] = newName;
    }
  };
}();

Now you can write:

console.log(dayName.getDay(3)); // prints "Wednesday"
dayObj.setDay(3, "Mercredi");
console.log(dayName.getDay(3)); // prints "Mercredi"

You can't do this with your second form of the function, because it has no memory from one call to the next.

like image 102
Barmar Avatar answered Sep 21 '22 10:09

Barmar


One case when you might return a function like that is when creating multiple similar event listeners. For example, suppose you have buttons named button1, button2, and button3. You can add click listeners like this (using JQuery for brevity):

button1.click(() => console.log(1));
button2.click(() => console.log(5));
button1.click(() => console.log(42));

This can be written instead as:

function makeLogger(x) {
    return () => console.log(x);
}

button1.click(makeLogger(1));
button2.click(makeLogger(5));
button1.click(makeLogger(42));

This makes an even bigger difference if you can't use the arrow function for compatibility reasons (not using Babel).

like image 20
Brian McCutchon Avatar answered Sep 23 '22 10:09

Brian McCutchon