Wrap a JS function transparently
Tags: javascript, webdev, typescript
Published: 2022-08-02 12:51:00

A wrapper function (aka a high order function) is a great way to augment a behavior of your other functions while still maintaining a separation of those concerns.

That pattern is widespread in JS/TS world and I consider myself a rather experiences user of it. However, sometime ago I came across a code snippet which demonstrated me that one detail is missed in my self-written wrapper functions.

The code snippet:

```js
function bindActionCreator<A extends AnyAction = AnyAction>(
  actionCreator: ActionCreator<A>,
  dispatch: Dispatch
) {
  return function (this: any, ...args: any[]) {
    return dispatch(actionCreator.apply(this, args))
  }
}
```

This wrapper function is from [Redux library](https://github.com/reduxjs/redux) but we may analyze it out of the library context. 

So _bindActionCreator_ takes 2 functions as arguments and returns a function which contains a composition of 2 input functions in the body. This is a good example of a utility wrapper function. But there is one place that hooked my attention. Honestly, if I need to create a similar function I would write just _actionCreator(args)_ without _apply(...)_ method call. So, let's find out why the function call via _apply_ method is used in the code snippet.

Let's consider a simple function:
```js
function f(name, email){
   return {name, email, this:this}
}
```

There is just one thing to pay attention, the function _f_ returns object which keeps **this** value of the function call. 

Let's write a simple wrapper function which actually does not add any logic but just returns a new function which contains function _f_ call inside:
```js
function wrap(f) {
    return function (...args){
      return f(...args)
    };
}
```

Now let's use the wrapper function:
```js
const wrappedF = wrap(f);
f(1,1) // {name: 1, email: 2, this: Window}
wrappedF(1,1) // {name: 1, email: 2, this: Window}
```

It seems that both calls are equivalent or **transparent**. 

But, let's call the functions like that:
```js
f.apply({a:1}, [1,1]) // {name: 1, email: 2, this: {a:1}}
wrappedF.apply({a:1}, [1,1]) // {name: 1, email: 2, this: Window}
```
Now results of the calls are not equivalent. Returned objects have different values for this key. 

Our wrapper function creates a distortion due to dynamic nature of **this** object **(1)**. **This** object only depends on how a function is called and can not be accessed or found via a scope chain. So _wrappedF_ and _f_ functions have the same input arguments but different **this** objects.

Our initial function _wrap_ can not transfer own **this** value (which e.g. we can set explicitly via _apply_ method) inside function _f_. But there is a very simple way to modernize initial wrapper function:

```js
function wrap(f) {
    return function (...args){
      return f.apply(this, args)
    };
}
const wrappedF = wrap(f)
f.apply({a:1}, [1,1]) // {name: 1, email: 2, this: {a:1}}
wrappedF.apply({a:1}, [1,1]) // {name: 1, email: 2, this: {a:1}}
```
Now our function wrap is transparent. It explicitly passes own **this** value in function _f_. Arguments and **this** are equivalent for the original and the wrapped version.

**(1)** - dynamic nature of **this** is true only for non-arrow functions. An arrow function does not have own **this** value but gets it from a closure (static nature). In case if function _f_ is defined as an arrow function, **this** value of such function is defined in moment of a creation and already does not depend on how function _f_ is called.


P.S 
In my practice I have never met a case where I really need to have a transparent wrapped function, but still it is useful to keep in mind that **this** can reach and punish you in any time=) 
Bless static scope!