Encapsulate and Moderate with Closures
Tags: javascript, discuss
Published: 2019-06-06 18:19:26

Have you ever found yourself wanting to modify and update a data structure throughout the life of your application? Take the following code:

```javascript
const obj = {}

const modifyObj = (key, value) => {
  obj[key] = value
  return obj
}
modifyObj('foo', 'bar') // Returns { foo: 'bar'}
modifyObj('biz', 'baz') // Returns { foo: 'bar', biz: 'baz' }
```

We have some object, `obj`, defined in our global scope, and a function, `modifyObj` that can accept a key/value pair that are assigned to the global object. We can see what happens when we invoke our function via the provided comments.

Given how our function is constructed and where our modified object is defined, is there anything that prevents us from directly interacting with the object outside of our function?

The answer is no:

```javascript
delete obj.foo // Yup I can do this!
// Or...
obj['foo'] = 'biz' // Totally valid - this is what our modifying function does!
```
This is not ideal. We really would like for an object that we can modify, but we'd also like to do so without exposing the object to the global scope. We can achieve this with closure!

Closures leverage what is known as a higher order function - a function that returns a function - to encapsulate variables and other data within a private scope. The returned function can access and modify that data, known as creating closure around it. 

What this means is, we can create our object within the context of a higher order function, and then modify it without exposing that to the global scope. Let's take a look at the code.

```javascript
const higherOrderFunc = () => {
  const obj = {}
  return function modifyObj(...args) {
    const [key, value] = args
    obj[key] = value
    return obj
  }
}

const modifyObj = higherOrderFunc()
modifyObj('foo', 'bar') // Returns { foo: 'bar'}
modifyObj('biz', 'baz') // Returns { foo: 'bar', biz: 'baz' } !!!
console.log(obj) // ReferenceError: obj is not defined!

// And I have no method of messing with the object from the outside!
```
Let's also walk through our code and talk about what's happening.

```javascript
const higherOrderFunc = () => {
  const obj = {}
  return function modifyObj(...args) {
    const [key, value] = args
    obj[key] = value
    return obj
  }
}
```
This is our closure. We create a higher order function that returns an inner function which retains knowledge of the outer `obj` variable. That way, we can invoke our function to modify the `obj`. 

```javascript
const modifyObj = higherOrderFunc()
```
Here, we invoke our higher order function to create our object and provide us with a setter function. Nothing has been done to the object quite yet.

```javascript
modifyObj('foo', 'bar') // Returns { foo: 'bar'}
modifyObj('biz', 'baz') // Returns { foo: 'bar', biz: 'baz' }
```
We operate on our object with our closure, and can see that the object updates as expected!

```javascript
console.log(obj) // ReferenceError: obj is not defined!
```
Finally, we try to log the object outside of our closure's scope. We'll get a reference error, which means we are trying to operate on a variable that does not exist in our current scope!

Hopefully you can find some use for closures in your current or upcoming work. Can you think of some uses for it right now? We'll be discussing one in my next post and how powerful closure is in that context.

*BONUS*: My function only allows for setters. But there's a way to extend the higher order function to also return a getter so we can check our object. Feel free to provide your solution in the comments below!