Hiding Variables and Closure in JavaScript

Scott Price
4 min readOct 1, 2018

--

I recently had a phone interview and was asked some questions that I could have answered better. The purpose of this series of blog posts is to help me remember these concepts, so next time I will have a better answer. If others find these posts useful, all the better.

Hiding Variables

As a developer, there are times when you want to control how other developers interact with your code. You may want to make sure certain variables in your code are only changed in a controlled way. Look at the following example:

const counter = {
count: 0,
increment(x = 1) {this.count = this.count + x},
decrement(x = 1) {this.count = this.count — x},
getCount() {console.log(this.count)}
}

The counter object has a count property and three methods. Two methods, with a default property of 1, to increase or decrease the value of count, and one method to display the value of count to the console. If we execute the following:

counter.increment();
counter.increment(5);
counter.increment();
counter.increment(11);
counter.increment();
counter.decrement(14);
counter.getCount();

The value of 5 is logged to the console. However, if we execute the following:

counter.count++;
console.log(counter.count);

The value of the count variable is increased by one and logged without using any of the defined methods.

In this example, we do not have control over how other developers interact with our count property. They can use the methods we have provided, but they can also directly access the count property by calling counter.count.

Closure

We can solve this problem using closure. A closure is created when you declare a function within another function. The inner function has access to the outer functions variables and parameters. If you expose the inner function, then you can access the outer functions variable and parameters in a controlled way, through inner function. One way of exposing the inner function is by returning it from the outer function. Consider the following code:

function counter() {
let count = 0;
const increment = (x = 1) => count = count + x;
const decrement = (x = 1) => count = count — x;
const getCount = () => console.log(count);
return {
increment,
decrement,
getCount
}
}

In this case we define counter as a function, instead of an object literal. First, the count variable is defined inside the function. It is private to the counter function. Then increment, decrement, and getCount are defined as functions inside the counter function. They have access to the count variable, because they are also declared within the counter function. Finally, increment, decrement, and getCount are returned from the counter function. Because of this, we can call them, and indirectly access the count variable, outside the counter function like this:

let myCounter = counter();
myCounter.increment();
myCounter.increment(5);
myCounter.increment();
myCounter.increment(11);
myCounter.increment();
myCounter.decrement(14);
myCounter.getCount();

Like in the previous example, 5 is logged to the console. However, if we attempt to access count directly:

myCounter.count++;
console.log(myCounter.count);

It does not work. ‘NaN’ is logged to the console. If we run:

myCounter.getCount();

We see that count is unchanged; it is still 5.

Immediately Invoked Function Expression (IIFE)

A problem with the previous example is that it creates more variables then are necessary. Both counter and myCounter are global variables. If a program only needs one counter, we can eliminate one of these variables using an IIFE.

const counter = (function() {
let count = 0;
const increment = (x = 1) => count = count + x;
const decrement = (x = 1) => count = count — x;
const getCount = () => console.log(count);
return {
increment,
decrement,
getCount
}
})();

In this example counter is the only global variable.

counter.increment();
counter.increment(5);
counter.increment();
counter.increment(11);
counter.increment();
counter.decrement(14);
counter.getCount();

As in the previous examples, 5 is logged to the console.

ES6 Modules

Another way to hide variables in modern JavaScript is with ES6 modules. Create a file, counter.js, with the following content:

let count = 0;
export const increment = (x = 1) => (count = count + x);
export const decrement = (x = 1) => (count = count — x);
export const getCount = () => console.log(count);

Import the exported functions from the counter.js module into the main module of your project (in this case index.js) like this:

import * as counter from ‘./counter.js’;

Then call functions from the imported counter.js module in the index.js module:

counter.increment();
counter.increment(5);
counter.increment();
counter.increment(11);
counter.increment();
counter.decrement(14);
counter.getCount();

Finally, import the index.js file into your html page using a <script> tag:

<!DOCTYPE html><head>
<title>Counter</title>
</head>
<body>
<script type=”module” src=”./index.js”></script>
</body>
</html>

When you load the html file in the browser, and look at the console, you will see that the value 5 has been logged. Within the index.js module you do not have direct access to the count variable in the count.js module, but you do have indirect access through the increment, decrement, and getCount functions that were imported from the count.js module.

Conclusion

This brief article does not exhaust all there is to say about hiding variables and closure in JavaScript. A more thorough explanation would include a discussion of execution context, lexical environment, and scope chain as you will find in this article. I believe I have achieved my goal, which was to present a basic understanding of how to hide variables and what closure is in JavaScript.

Other Stories in this Series:

--

--

Scott Price

Front End Developer with Information Security Experience. See my resume and portfolio at www.scottaprice.com