Skip to content

Instantly share code, notes, and snippets.

@Jauny
Last active January 7, 2017 08:19
Show Gist options
  • Save Jauny/cffeb890898a069510e9352475e5dbf6 to your computer and use it in GitHub Desktop.
Save Jauny/cffeb890898a069510e9352475e5dbf6 to your computer and use it in GitHub Desktop.

Closures in javascript

a normal function

declare the function

var add = function(x, y) {
  return x + y;
};

now we can call the function using the variable add

> add(2, 3)
> 5

We can also reference the function without calling it, if we don’t add parenthesis and arguments:

> add
> function (x,y) { return x+y; }

2 things happen when we call add(5, 3):
First, the add part is replaced (or interpreted) by the actual function declaration (function (x, y) { return x + y; },
then the parenthesis with the arguments are added, and the function runs.

So add(3, 5) is the same as:

> function(x, y) {
>   return x + y;
> }(3, 5)
> 5

closures

A closure if a function that returns another function.
Let's leverage the add function we just used to create a new function called addTen. It allows us to add 10 to any number.

var addTen = function(x) {
  return add(x, 10);
}

The same way, we can now reference this function with the variable addTen. We must add parenthesis to run the function:

> addTen
> function (x) { return add(x, 10) }
> 
> addTen(5)
> 15

Note that now, add(x, 10) gets printed when we reference the function. It looks like we are calling add since there are parenthesis, but the function isn’t being called yet.

The reason is Javascript’s double interpretation cycle. The code is interpreted twice: once at load time (when the script is loaded) and then at run time (when the code is actually called). The first time the code is interpreted:

  • all variables are replaced by what they actually hold. For instance, add would be replaced by function (x, y) { return x + y;}
  • all first level function calls are ran. add(5,3) would run and be replaced by 15

What's important is "first level". In the example of our closure, the return add(x, 10) part is "nested". It's inside another function, so it won't run unless the parent function is ran.

Let's look at an example; Say you load the following file:

var add = function (x, y) {
  return x + y;
};
var addTen = function (x) {
  return add(x, 10);
};

add
add(5, 3)

addTen
addTen(5)

the interpreted file, once loaded, would look like this: (this is not totally true but irrelevant here)

var add = function (x, y) {
  return x + y;
};
var addTen = function (x) {
  return add(x, 10);
};

function (x, y) {
  return x + y;
}
8

function (x) {
  return add(x, 10);
}
15

In the example of our closure, when interpreting addTen, the part with add(x, 10) isn’t executed despite parenthesis. That’s because the parent is not being ran (addTen is without parenthesis).

passing around function references

Having the function declaration in the variable is not only useful to be able to call it multiple times at multiple places, but also to "pass it around". For example, to pass it as an argument to another function.

Let's say we have more math functions than just add. multiple, for example:

var multiple = function (x, y) {
  return x * y;
};

And instead of the addTen function, we want an modeTen function, which takes a number and an incrementation mode (add or multiple) and will combine the number and 10 using the incrementation mode passed to it:

var modeTen = function(x, mode) {
  return mode(x, 10);
};

Here we can now call our modeTen function with a number and either our add or multiple function:

> modeTen(5, add)
> 15

> modeTen(5, multiple)
> 50

Why does it matter?

It matters to understand how functions are referenced, passed and called because this is something we keep doing in javascript when dealing, for example, with callbacks:

var functionWithCallback = function (name, callback) {
  console.log("hello " + name);
  
  callback(name);
};

This is a very simple function that prints a name and calls a callback once it’s done.
The callback function could be just a function we use to let us know that the name was successfully printed:

var callback = function(name) {
  console.log("successfully printed " + name);
};

> functionWithCallback('jonathan', callback);
> "hello jonathan"
> "successfully printed jonathan"

Closures are often wrongfully abused to fix a bug coming from a bad understanding of all this; Look at an example using our previous functionWithCallback. Let's say you are using an API you are not really familiar with (could be something like res.render in nodejs or anything), and you want to make sure that your callback will be called with the name variable, you may write something like this:

functionWithCallback('jonathan', callback('jonathan'));

Note that you are passing callback('jonathan') as an argument. As we've just seen, callback('jonathan') will actually be called at load time, so you end up passing the result of the function instead of the function itself: functionWithCallback('jonathan', 'successfully printed jonathan'). Obviously not what you wanted.

But now faced with a bug, and not understanding the issue, most engineers with mess around and end up solving this problem with a fixture:

functionWithCallback('jonathan', function() {
  callback('jonathan');
});

Engineers often end up in this situation because this callback syntax looks familiar, as it is the syntax used to declare a callback inline, when it's not in a variable.

As we know, the callback function is actually being called inside functionWithCallback with name passed to it as we want, so it’s enough to simply pass a reference of the callback function as argument; As we saw, using the callback variable without parenthesis:

functionWithCallback(‘jonathan’, callback);

Another example is in React, when passing a function as a prop. Let’s say we have the following component:

class Parent extends React.Component {
  onButtonClick() {
    console.log(‘clicked button‘);
  }

  render() {
    <Button id=”1” onClick={this.onButtonClick} />
  }
}

In this example, we to pass the onButtonClick to the button component. And when then button is clicked, the function is called and all is good.

The issue here is that if the onButtonClick function had a id argument, the button would not know about what argument to pass:

class Parent extends React.Component {
  onButtonClick(id) {
    console.log(‘clicked button  + id); // note now we pass an id
  }

  render() {
    <Button id=”1” onClick={this.onButtonClick} />  // Button has no idea what “id” is
  }
}

So we need to explicitly tell the button what the id is and to pass it as an argument when calling the function.
One of the solution is to use a closure:

render() {
  <Button id=”1” onClick={() => this.onButtonClick(“1”)} />
}

In this case it would work, because thanks to the closure the inner function this.onButtonClick(“1”) is nested and doesn’t get called at load time.

Another solution would be to use an inner onClick function on the button component, which is often cleaner (in my opinion):

class Parent extends React.Component {
  onButtonClick(id) {
    console.log(‘clicked button  + id);
  }

  render() {
    <Button id=”1” onClick={this.onButtonClick} />
  }
}

Class Button extends React.Component {
  onClick() {
    this.props.onClick(this.props.id);
  }
}

This is also only possible if the element receiving the function as props is a component you control; If the component was a native HTML <button> for example, this wouldn’t be an option.

A last general comment about passing functions through multiple levels. In our example of the onButtonClick that takes an id as argument, you only have to explicitly pass the id argument in the component that will actually call the function, and can only pass the function by reference to other components it goes through;

class Root extends React.Component {
  onButtonClick(id) {
    console.log(‘clicked button  + id);
  }

  render() {
    <Section onButtonClick={this.onButtonClick} />
  }
}

Class Section extends React.Component {
  render() {
    <button id=”1” onClick={() => this.onButtonClick(“1”)} />
  }
}

Note here the onButtonClick is from the Root component and we pass the function down to a button element, through the Section component. Despite choosing the closure solution, which we use on the props of the button, we don’t have to explicitly tell Section about the id argument and just pass it onButtonClick as a reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment