Functional Binding in JavaScript
Tags: javascript, this, bind
Published: 2020-01-05 16:09:41

If you already spent some time coding with JavaScript, you should come across a `bind()` function. For beginners, it is not an easy concept to understand. Let's try to analyze a few simple examples and give clarification on what does it do, and how can it be applied.

## Understanding Keyword `this`

To understand what `bind()` do, first we need to clarify what is `this`. And it differs on where it is being used.

In the **global** context, the keyword `this` will refer to the global Window object. If you open your browser console and write `this`, you'll see a Window object with all the properties.

```js
console.log(this) // Window {parent: Window, opener: null, …}
```

In the **function** context, it is a little bit tricky, because it depends on how the functions are being called. If we have a simple function call, without the specified `this` context, by default `this` will be assigned to the global Window object.

```js
function getContext() {
  return this;
}

getContext() // Window {parent: Window, opener: null, …}
```
If you will call a function with a methods `.call()` or `.apply()`, you can set the context to `this` by providing the first argument.

```js
function getContext() {
  return this;
}

// creating custom object
const user = { age: 20 };

// calling and setting functions context to the object "user"
getContext.call(user) // { a: 20 }
```

If the function is being called as an object method, `this` keyword will refer to the object, where the method is being called on.

```js
const user = {
  age: 20,
  getAge: function() {
    return this.age;
  },
  getContext: function() {
    return this;
  }
}

user.getAge() // 20
user.getContext() // {age: 20, getAge: ƒ, getContext: ƒ} 
```

## Function `bind()` Method

Now that we recalled what keyword `this` means, it should be simpler to understand what problem solves `bind()` method. 

By definition, `bind()` is a function prototype method that creates a **new function** with the same body and scope as the original one and sets a new context value from the first provided argument to the keyword `this`. 

```js
function getName() {
  return this.name;
}

getName() // undefined, because "this" refers to Window
getName.bind({ name: "Bob" }) // Bob
getName.bind({ name: "Jane" }) // Jane
```
That was a very simple use case. The real problem occurs when we use functions as object methods and assign them to variables or use as callbacks. Then they to loose `this` context.

```js
const user = {
  age: 20,
  getAge: function() {
    return this.age;
  }
}

user.getAge() // 20;

const getUserAge = user.getAge;
getUserAge() // undefined
```
`getUserAge()` returns undefined, because it lost context of the object. When we assigning object method, in this case `getAge`, to a variable, it no longer exists as a method, and has no reference to the `user` object. It becomes an independend function and is equivivalent to:
```js
const getUserAge = function() {
  return this.age; // "this" will refer to "window" object
}
```
To add `user` object context again to the function, we need to use `.bind()` method at the time we assigning method to the variable:
```js
const getUserAge = user.getAge.bind(user);

getUserAge(); // 20
```

Another real-world example is handling DOM element events. Again, if you will use an object method, that has `this` keyword, it will lose context, and `this` will be reassigned to the DOM element itself:
```js
const user = {
  name: 'Bob',
  greet: function() {
    return 'Hello ' + this.name;
  }
}

const button = document.getElementById('btn');
button.addEventListener('click', user.greet); // Hello undefined
button.addEventListener('click', user.greet.bind(user)); // Hello Bob
```
The same lost context problem happens when using object methods as callbacks for `window.setTimeout()`. If the method will not be bound, the keyword `this` will be reassigned to the global "window" object.

## Passing Arguments To The `bind()` Method

`bind()` method accepts a list of arguments after the first context argument. The use-case for that would be to create new functions with pre-specified arguments:
```js
function add(a, b) {
  return a + b;
}

add(2, 3); // 5

const add7 = add.bind(null, 7);

add7(5); // 12
add7(10); // 17
```
As we don't need to provide any context for the new function, we set the first argument to `null`. Any other following arguments, provided to the `bind()` method will be replaced and set as initial arguments for the new function. The number 7 will be replaced as an argument "a", and the second argument "b" will be provided with new function call `add7(5)` as 5.

I have never used `bind()` for setting initial arguments to the new functions, but I imagined as a really useful case could be to write your own class name generator and use it for setting React class names for components:

```jsx
function prefixer(s1, s2) {
  return s1 + "-" + s2;
}

const listPrefixer = prefixer.bind(null, "shopping-list");

function ShoppingListItem(props) {
 return <li className={listPrefixer("item")}>{props.item}</li>
}
```

After rendering component to the DOM, the list element will have a class name of "shopping-list-item".


And that's about it. A brief intro to the making bound functions. Does it make it more clear now?