Functional Programming (FP) is awesome. Some of its key ideas inspired a lot of the JS practices and tools we use here at Rangle, especially React and Redux.
Even though JS is not strictly a functional language, you can get a lot of the same value you get from FP due to JavaScript's flexible nature and some amazing tools people have created.
If you really want to master functional JS, one route is to learn a completely functional language and take that
knowledge back to your JS programming.
Why not just learn more functional JS? I'm glad you asked!
Burn the boats
A lot of concepts in functional programming are difficult at first because they are fundamentally different than a lot of the things you learn in imperative languages. Moving to a functional style of programming isn't like learning a new framework; it's closer to how you probably first felt when you were learning about inheritance, loops, or pointers, for example.
Since the concepts can be in stark contrast to imperative ones, it can be hard to break out of your current way of thinking and learn the fundamentals. In programming, many concepts are easier to understand by relating them to things we already know, so it can be tempting to try and compare things in FP to things we know from non-Functional languages.
By getting into a completely functional language, it doesn't let you do things the "normal" way and forces you to do things in a fully functional way. It can be a bigger upfront investment, but it pays great dividends. When attempting to write good functional JS, I often find myself thinking "how would I do this in one of the FP languages I've learned?".
A library for what, exactly?
There are tons of great FP and FP-inspired libraries for JS-- Immutable, Ramda, React, Redux, just to name a few. When you're learning these tools, if you're not familiar with the concepts they're trying to facilitate, it can be harder to see the point or really know how best to use them.
By using a functional language where these concepts (currying, composition, immutability, pure functions, etc) are the standard way of doing things, it really helps nail down the WHY of all these great libraries and you get a first-class look at what they are trying to bring into JS.
Bonus: It concurrently reduces your reliance on these libraries when you could implement some of it from scratch, or really helps you dig into the code if you feel like contributing!
Let the language do the heavy lifting
It's actually a lot of fun and pretty straightforward to jump into FP using only functions that are built into JavaScript: map, filter, reduce and Object.assign are some great examples, along with the ...rest and ...spread operators introduced in ES2015. If you haven't checked these out, just go for it and start learning FP right away!
However, once you get a little deeper into FP, two problems arise. First, to get a more advanced FP setup, you'll need additional tools and libraries above and beyond what JS offers natively, which can require a lot of configuration/setup to get everything working together. Secondly, even with such a setup, the programmer still has to be very diligent.
As much as libraries and patterns guide us, programmers make mistakes. We get tired, frustrated, and sometimes it's still really tempting to just turn off type-checking for a difficult function or to mutate some DOM elements manually to save time and headaches. It happens.
The problem we're facing here is that no matter what setup you're using, you're still programming in JS which is not a strictly functional language. You can use Redux and have a pure reducer, or you could mutate the DOM in the middle of that reducer, or make an API call, or literally anything else. JS won't stop you, Redux might yell at you, but it's still ultimately up to you as a programmer to make sure you're applying the pattern correctly. Libraries and linters help, but they can only do so much.
If you use a purely functional language, it will help you learn the ropes by enforcing guarantees about the code you're writing. Programs won't compile if you've screwed up the type signatures. Errors will be thrown if you write an impure function. Causing side effects will need to happen in a very specific and guided way, and any other way will make the compiler angry.
At first, this can be really tough and adds to the large initial investment. Trying to implement a new concept and running into umpteen compiler errors can be really frustrating. With enough work though, it becomes the style you're accustomed to and the language itself will let you know when you've strayed from the path of functional goodness. Once you get an intuitive feel for a purely functional style, it becomes much harder to trip up in JS because it will just "feel wrong" to abandon the FP patterns.
Have fun!
I hope I've convinced you to spend a weekend picking up a functional language! By no means do you need to become an expert, but learning something so different from your day-to-day can be exciting and invigorating!
Have fun, go learn some cool new FP concepts, and I guarantee your JS skills will benefit. You may even end up finding a cool new concept and bringing that back into the JS world, which benefits everyone!
P.S: There are many functional languages or languages that allow a functional style available like Haskell, Clojure, or Erlang, just to name a few. A relatively new language I highly recommend is Elm which has been designed from the ground up for front-end development, has fantastic compiler messages, and has a great focus on making the language an easy transition from JS for beginners. The elm-architecture even had a hand in inspiring Redux, so once you get the syntax down building apps will feel very familiar!
Happy coding :).