Functional JavaScript: Decoupling methods from their objects

16,334 reads

One thing I always end up doing in my project is decoupling methods from their objects. map , filter and reduce are not the only ones, but they are definitely among the first to be given freedom.

Decoupling a method allows it to be free of the limitations imposed by their parent object as well as giving us more freedom in the ways we can express our code.

So what does that look like?

To keep things simple, let’s limit ourselves to just extracting map from Array. Fortunately JavaScript’s prototypal inheritance makes this easy for us as the function we want is just sitting at Array.prototype.map . One cool thing about JavaScript is that we can call this method directly. We just have to use .call because map expects a this parameter.

Sprinkle in a little curry (future article) and we end up with this neat little one liner…

const map = f => x => Array.prototype.map.call(x, f)

We can now call our map function sans-Array!

Alternate ways to map

There are many different ways of calling map and due to V8 engine optimizations and there’s really no difference in performance.

Any performance difference is not significant and these numbers will change every time. The takeaway should be these methods are equal.

How does decoupling make my life better?

Now that is a great question! Arguably the best question. I think this is best explained with code instead of words, so let’s just dive straight in.

document.querySelectorAll (and similar methods) do not return an Array, they return a NodeList and a NodeList does not contain a map method. There are some magic tricks you can do to convert a NodeList into an Array, but conversion is not necessary as our map can enumerate over a NodeList with as if it were an Array.

We can even map over a string without the need to first cast it to an array of characters.

Decoupling allows us to easily turn an object mapping into a list mapping:

We can even map over objects.

Decoupling allows us to compose functions:

Decoupling (with curry) allows us to partially apply the function arguments and create new functions.

Say goodbye to this !!!

In this example cat.speak works but catSpeak does not work because the this context changes. What a pain! Instead we can decouple the speak method and never worry about this ever again!

Then we can create new functions that use our decoupled functions.

Summary

Today we have learned there many benefits of decoupling methods and extracting them from their objects. Decoupling allows a function to be used in more places and different types of objects as well as opening it up to be composed with other functions. We also eliminate all references to the this context, which that alone is enough for me!

I know it’s a small thing, but it makes my day when I get those follow notifications on Medium and Twitter (@joelnet). Or if you think I’m full of shit, tell me in the comments below.

Cheers!

Related Articles

Tags