How to uncurry this
Tags: javascript, bind, call, function
Published: 2019-03-15 19:36:56

---
title: How to uncurry this
published: true
description: Deep dive to the realm of bind, call, apply functions. Demystification of uncurryThis helper.
tags: javascript, bind, call, function
---

A friend of mine send me a snippet of code and asked me if I could help him see what's going on under the hood. He knew what he can do with it, but was curious (as every developer should be) if understanding the magic behind it would open him a whole lot of new options how to write code.

This is the piece of code:

```js
const uncurryThis = Function.bind.bind(Function.prototype.call);
```

Do you ever find yourself going through a source code of a library and you stumble upon a piece of code that uses `bind()`, `call()`, `apply` or even their combination, but you just skip to the next line, because it's obviously some sort of black magic?

Well, let's deep dive.

# Context, Scope, Execution context

In this article we'll be talking a lot about context, so let's clarify what it is right from the start so there's no confusion as we go along.

In many cases there's a lot of confusion when it comes to understanding what **context** and **scope** are. Every function has both scope and context associated to it but **they're not the same**! Some developers tend to incorrectly describe one for the other.

## Scope

**Scope is function based** and has to do with the visibility of variables. When you declare a variable inside a function, that variable is private to the function. If you nest function definitions, **every nested function can see variables of all parent functions within which it was created**. But! Parent functions cannot see variables declared in their children.

```js
// ↖ = parent scope
// ↖↖ = grand parent scope
// ...

const num_global = 10;

function foo() {
  // scope has access to:
  // num_1, ↖ num_global
  const num_1 = 1;

  function bar() {
    // scope has access to:
    // num_2, ↖ num_1, ↖↖ num_global
    const num_2 = 2;

    function baz() {
      // scope has access to:
      // num_3, ↖ num_2, ↖↖ num_1, ↖↖↖ num_global
      const num_3 = 3;
      return num_3 + num_2 + num_1 + num_global;
    }

    return baz();
  }

  return bar();
}

console.log(foo()); // 16
```

## Context

**Context is object based** and has to do with the value of `this` within function's body. `This` is a reference to the object that executed the function. You can also think of a context in a way that **it basically tells you what methods and properties you have access to on `this`** inside a function.

Consider these functions:
```js
function sayHi() {
  return `Hi ${this.name}`;
}

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

### Scenario 1:

```js
const person_1 = {
  name: "Janet",
  sayHi,
  getContext,
  foo() {
    return "foo";
  }
};

console.log(person_1.sayHi()); // "Hi Janet"
console.log(person_1.getContext()); // "{name: "Janet", sayHi: ƒ, getContext: ƒ, foo: ƒ}"
```

We have created an object `person_1` and assigned `sayHi` and `getContext` functions to it. We have also created another method `foo` just on this object.

In other words `person_1` is our `this` context for these functions.

### Scenario 2:

```js
const person_2 = {
  name: "Josh",
  sayHi,
  getContext,
  bar() {
    return "bar";
  }
};

console.log(person_2.sayHi()); // "Hi Josh"
console.log(person_2.getContext()); // "{name: "Josh", sayHi: ƒ, getContext: ƒ, bar: ƒ}"
```

We have created an object `person_2` and assigned `sayHi` and `getContext` functions to it. We have also created another method `bar` just on this object.

In other words `person_2` is our `this` context for these functions.

#### Difference

You can see that we have called `getContext()` function on both `person_1` and `person_2` objects, but the results are different. In scenario 1 we get extra function `foo()`, in scenario 2 we get extra function `bar()`. It's because each of the functions have different context, i.e. they have access to different methods.

### Unbound function

When function is unbound (has no context), `this` refers to the global object. However, if the function is executed in strict mode, `this` will default to `undefined`. 

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

testUnboundContext(); // Window object in browser / Global object in Node.js

// -- versus

function testUnboundContextStrictMode() {
    "use strict";
    return this;
}

testUnboundContextStrictMode(); // undefined
```

## Execution context

This is probably where the confusion comes from.

> Execution context (EC) is defined as the environment in which JavaScript code is executed. By environment I mean the value of this, variables, objects, and functions JavaScript code has access to, constitutes its environment.
>
> -- <cite>https://hackernoon.com/execution-context-in-javascript-319dd72e8e2c</cite>

**Execution context** is referring not only to value of `this`, but also to scope, closures, ... The terminology is defined by the ECMAScript specification, so we gotta bear with it.

# Call, Apply, Bind

Now this is where things get a little more interesting.

## Call a function with different context

Both `call` and `apply` methods allow you to call function in any desired context. Both functions expect context as their first argument. 

`call` expects the function arguments to be listed explicitly whereas `apply` expects the arguments to be passed as an array.

Consider:

```js
function sayHiExtended(greeting = "Hi", sign = "!") {
  return `${greeting} ${this.name}${sign}`;
}
```

### Call

```js
console.log(sayHiExtended.call({ name: 'Greg'}, "Hello", "!!!")) // Hello Greg!!!
```

Notice we have passed the function arguments explicitly.

### Apply

```js
console.log(sayHiExtended.apply({ name: 'Greg'}, ["Hello", "!!!"])) // Hello Greg!!!
```

Notice we have passed the function arguments as an array.

## Bind function to different context

`bind` on the other hand does not call the function with new context right away, but creates a new function bound to the given context.

```js
const sayHiRobert = sayHiExtended.bind({ name: "Robert" });
console.log(sayHiRobert("Howdy", "!?")); // Howdy Robert!?
```

You can also bind the arguments.

```js
const sayHiRobertComplete = sayHiExtended.bind(
  { name: "Robert" },
  "Hiii",
  "!!"
);
console.log(sayHiRobertComplete()); // Hiii Robert!
```

If you do `console.dir(sayHiRobertComplete)` you get:

```
console.dir(sayHiRobertComplete);
// output
ƒ bound sayHiExtended()
	name: "bound sayHiExtended"
	[[TargetFunction]]: ƒ sayHiExtended(greeting = "Hi", sign = "!")
	[[BoundThis]]: Object
		name: "Robert"
	[[BoundArgs]]: Array(2)
                0: "Hiii"
                1: "!!"
```

You get back an *exotic object* that wraps another function object. You can read more about *bound function exotic objects* in the official ECMAScript documentation [here](https://www.ecma-international.org/ecma-262/6.0/#sec-bound-function-exotic-objects).

# Usage

Great, some of you have learned something new, some of you have only went through what you already know - but practice makes perfect.

Now, before we get back to our original problem, which is:

```js
const uncurryThis = Function.bind.bind(Function.prototype.call);
```

let me present you with a problem and gradually create a solution with our newly acquired knowledge.

Consider an array of names:

```js
const names = ["Jenna", "Peter", "John"];
```

Now let's assume you want to map over the array and make all the names uppercased.

You could try doing this:

```js
const namesUppercased = names.map(String.prototype.toUpperCase); // Uncaught TypeError: String.prototype.toUpperCase called on null or undefined
```

but this **WILL NOT WORK**. Why is that? It's because `toUpperCase` method is designed to be called on string. `toUpperCase` itself does not expect any parameter.

So instead you need to do this:

```js
const namesUpperCased_ok_1 = names.map(s => s.toUpperCase());
console.log(namesUpperCased_ok_1); // ['JENNA', 'PETER', 'JOHN']
```

## Proposal

So instead of doing `names.map(s => s.toUpperCase())` it would be nice to do, let's say this `names.map(uppercase)`.

In other words we need to create a function that accepts a string as an argument and gives you back uppercased version of that string. You could say that we need to *uncurry* `this` and pass it explicitly as an argument. So this is our goal:

```js
console.log(uppercase("John")); // John
console.log(names.map(uppercase)); // ['JENNA', 'PETER', 'JOHN']
```

## Solution

Let me show you, how can we achieve such a thing.

```js
const uppercase = Function.prototype.call.bind(String.prototype.toUpperCase);
console.log(names.map(uppercase)); // ['JENNA', 'PETER', 'JOHN']
```

What has just happened? Let's see what `console.dir(uppercase)` can reveal.

```
console.dir(uppercase);
// output:
ƒ bound call()
    name: "bound call"
    [[TargetFunction]]: ƒ call()
    [[BoundThis]]: ƒ toUpperCase()
    [[BoundArgs]]: Array(0)
```

We got back a `call` function, but it's bound to `String.prototype.toUpperCase`. So now when we invoke `uppercase`, we're basically invoking `call` function on `String.prototype.toUpperCase` and giving it a context of a string!

```js
uppercase == String.prototype.toUpperCase.call
uppercase("John") == String.prototype.toUpperCase.call("John")
```

## Helper

It's nice and all, but what if there was a way to create a helper, let's say `uncurryThis`, that would accept a function and *uncurried* `this` exactly like in the `uppercase` example?

Sure thing!

```js
const uncurryThis = Function.bind.bind(Function.prototype.call);
```

OK, what has happened now? Let's examine `console.dir(uncurryThis)`:

```js
console.dir(uncurryThis);
// output:
ƒ bound bind()
    name: "bound bind"
    [[TargetFunction]]: ƒ bind()
    [[BoundThis]]: ƒ call()
    [[BoundArgs]]: Array(0)
```

We got back a `bind` function, but with `call` function as its context. So when we call `uncurryThis`, we're basically providing context to the `call` function.

We can now do:

```js
const uppercase = uncurryThis(String.prototype.toUpperCase);
```

which is basically:

```js
const set_call_context_with_bind = Function.bind.bind(Function.prototype.call)
const uppercase = set_call_context_with_bind(String.prototype.toUpperCase);
```

If you know do `console.dir(uppercase)`, you can see we end up with the same output as we did in **Solution** section:

```
console.dir(uppercase);
// output:
ƒ bound call()
    name: "bound call"
    [[TargetFunction]]: ƒ call()
    [[BoundThis]]: ƒ toUpperCase()
    [[BoundArgs]]: Array(0)
```

And viola, we now have a utility to unbound `this` and pass it explicitly as a parameter:

```js
const uncurryThis = Function.bind.bind(Function.prototype.call);
const uppercase = uncurryThis(String.prototype.toUpperCase);
const lowercase = uncurryThis(String.prototype.toLowerCase);
const has = uncurryThis(Object.prototype.hasOwnProperty);

console.log(uppercase('new york')); // NEW YORK
console.log(uppercase('LONDON')); // london
console.log(has({foo: 'bar'}, 'foo')); // true
console.log(has({foo: 'bar'}, 'qaz')); // false
```

# We're done

Thanks for bearing with me to the very end. I hope you have learned something new and that maybe this has helped you understand a little the magic behind `call`, `apply` and `bind`.

# Bonus

Whoever might be interested, here's a version of `curryThis` without using `bind`:

```js
function uncurryThis(f) {
  return function() {
    return f.call.apply(f, arguments);
  };
}
```