91 comments

[ 4.8 ms ] story [ 167 ms ] thread
JavaScript is an antpattern.
The flagged comment was accurate - post claims FP in javascript is an antipattern, but then says FP is the most sane way to write javasript.

Ergo author is claiming javascript is an antipattern, tldr clojurescript. /shrug

that's a misrepresentation. post claims FP in javascript is an antipattern, so use FP language that transpiles to javascript instead.
From the post:

    Basically, write Javascript without functional programming techniques. That doesn’t seem like a good solution.
So . . . what am I misrepresenting?
JS is an antipattern for itself.
Seems like the author discovered the curse of the excluded middle: http://queue.acm.org/detail.cfm?id=2611829
Interesting article, but I think F# (and other impure FP languages) show pretty clearly that you can have "mostly functional" programming without causing chaos.
I like Javascript. As a language. It's fun, enjoyable, and I'm productive in it. There I said it.

I don't mind exploring interesting avenues like immutability, jsx, typescript, declarative or functional styles. I like that JS has enough flexibility to make all of these possible.

I get the fatigue about the endless stream of new frameworks, libraries, approaches, and "new hotness". But I became much more relaxed about it all when I realised it's all completely optional. I can just stick with vanilla JS if I want to, and cherry-pick interesting things as they whizz by. It's the sushi train of programming environments :)

LISP in JS sounds great, I might give it a try. But this does raise a conundrum... if LISP is the ultimate programming language because you can write all the others in LISP, then the fact that this is a LISP written in JS makes it...what?

unfortunately this approach does not scale past single developer or multiple klocs of code unless you're really disciplined, but then wouldn't that cognitive effort be better spent elsewhere?
I get the impression that the OP wasn't talking about a team environment either? I could be wrong...
I've seen multiple klocks of code written in Java and C that are taking minutes to handle database operations, unable to process parallel network requests, and choking on errors. Watching new features get added is exciting in the same way it's ensorcelling to watch someone assemble a house of cards.

I'd love a tool that enabled me to spend my cognitive currency how I want to, but so far all I've found are tools that have disguised their expenses in new and interesting ways, like tranches of a collateralized debt obligation.

i don't think i disagree with you and (i think) neither does the author. argument (as i understand it) is that rather than piling on features that don't really fit and have complex interference you could use a better tool.
I think this is one of the most sensible questions to ask wrt. JS (except where you have no choice but to use it).
LISP isn't the ultimate programming language because you can write all others in it. You can write any Turing-complete language in any other.
True, you can write a language parser in any other language.

That's not what I meant. I may have not been clear enough.

What did you mean?
If I had to guess: that macros in LISP are natural, owing to the fact that its syntax are all s-exps which make it parsing it easier than in other languages?
I had to go down a small rabbit hole of my own ignorance here.

My initial thought was that since JS is the target environment for a LISP compiler, it would necessarily have to be more flexible and "powerful" (whatever that means). With a bit more thought I realised that that's not the case.

Thanks for the prompt to look into this more, and learn :)

When you say you like JS as a language what do you mean ? ES5 or ES6 or ES7 or transpiling ?
They're the same language. It's incremental additions without breaking backward compatibility.

This isn't Python we're talking about here ;)

I know that they are the "same" language. But having to maintain transpiled ES5 legacy app kills the joy for me.
You are right, it is great that there are endless options and styles to choose. A good chunk of the work is already done for probably every project imaginable! It's nice, especially for personal projects. And for multiple developers, well, at that point it's just a nice exercise in working with others to decide which framework(s) to use :)

Yes, in some environments you don't get to choose, but why blame the language for that?

A Lisp is a good lightweight way of expressing things. You can write a Lisp with any language. The main plus of a Lisp is that you are not burdened by Syntax and boilerplate. You can use Metaprogramming in an unconstrained way. We have Lisps written in most popular languages.

Python has Hy (newest Lisp on the block), Java has Clojure (currently the most popular one), Erlang has LFE (For BEAM just like Clojure is for JVM), Most scheme (kinda like lightweight lisp with a 100 variants) interpreters are in C. What does that make them? Nothing more than what they already are.

What makes Lisp a Lisp is Functional Programming and Syntax where the program itself is treated as Data (Very good for easy macros that transform like a Transformer) and S-Expressions (Every thing is an S-Expression). Not because you can write all others in Lisp.

There are so many JS/Node developers now, and I have worried that JS will ruin dynamic languages for a lot of people, so it's encouraging to hear this written about ClojureScript: "As an average Javascript/Node developer, it hasn’t been difficult for me to learn the language or the ecosystem"
It's an anti-pattern to call some "overly broad category of things" an anti-pattern.
Coming from Clojure to ClojureScript, I must say I have had some hard times with the dynamic, mutable, APIs that a lot of js libraries have.

Even though interop is possible and not difficult, I am so much more comfortable using cljs wrappers (there are a lot) or in my part of the world (cljs - land). One reason is that the clojure way (tm) is to use immutable data and pure functions. It bugs me to enact stateful changes.

One way out is to have a datastructure that stores the state of the entire browser (what url am i on, what's in local storage?) and change the datastructure while some unspeakable side effecting function observes and updates either localstorage, or browser history, or etc.

In Clojure 90% of my code is datastructures, manipulating them, and sending them back. Partly because servers tend to be way less stateful than UIs, and partly because it feels like there is more to explore in Clojure without going into java, compared to cljs/js.

In my opinion the top rated comment is right on point there: "I’d say that ImmutableJS is your anti-pattern here, not FP in JavaScript as a whole."
(comment deleted)
I agree - I use ImmutableJS in one of my projects and the pros vs cons are substantial - it's hard to keep track of when something is Immutable or not and it has been slowly infecting more and more of my codebase.

I would be interested in hearing strategies of mitigating this, my first step has been to let Immutable creep through the project, but adopt a convention of creating a layer through which guarantees JS output - anything that is logic related in my redux layer is Immutable, anything which is in my presentational react layer is JS.

The difficulty then, is at input points where I need to always remember to deal with nested data structures too.

It feels like a type checker would be of great use here to add additional guarantees about any data

Interesting you should say that. I wrote a Reddit comment about a year ago listing reasons why I generally advise against use of Immutable.js, and the "infectious" API is exactly one of the reasons that I listed ( https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abra... ).

Also worth noting that if you are going to do Immutable -> POJO conversions, you should avoid using `toJS()` as much as possible. The conversion process is expensive, _and_ it always creates new object references. Either use `getIn()`, or use memoized selectors to ensure the conversion only happens when the data actually changed.

Yep memoized selectors was on my list of things to look at - great tip!

My philosophy is when providing the POJO from the immutable data structure is to select the absolute minimum from the bigger object, which I suppose is in line with your advice on using getIn

I have a few large React apps that have been using mostly Immutable.JS from the very beginning, so I rarely run into issues where I need to think whether what I'm dealing with is an Immutable.JS object or plain JS objects. I can see an issue if you are incrementally converting an app to Immutable.JS and dealing with a mix of plain JS objects though.

I have heard criticisms of lisp macros as making it a write-once language. If you're not working on a team then maybe it's fine, but other people aren't gonna want to figure out how your macros work.

This is why a professional developer needs to document their code. If they don't do that, then they are NOT a professional.

Plus they are selling themselves short. If you want to fully learn something you must teach it. By documenting your code you are teaching the other developers on the team and this will lead you to much deeper understanding than the hackers who churn out code all day.

This post struck home with me. But I realized that the root cause for the problem is the many ways to do FP (and, notably, immutable) in JS. What doesn't help here is that all ways have some major downsides. ImmutableJS has a huge API that works pretty different from everything else. Ramda changes all the time. Lodash, by virtue of not changing all the time ever since underscore was first released, has some pretty weird and unexpected function names and behaviors.

If JS had more builtin functional primitives (i.e. well beyond Array.prototype.map and friends) this problem would be much smaller.

Similarly, I think another way out of this antipattern is to settle with the team on a single way to do FP. This disqualifies ImmutableJS by definition, because 3rd party apis tend to want arrays and objects. But most other options are open, I guess.

I wouldn't go as far as to call it an anti-pattern, but the lack of native persistent data structures does make functional programming a decidedly second-class citizen in the JS world.

We can either choose to use a library like ImmutableJS instead of regular JS objects and suffer the impedance mismatch and exponential increase in verbosity, or use regular JS objects and make full copies every time we want to change any piece of data.

It's a very unfortunate blemish on an otherwise surprisingly pleasant experience (functional programming in JS), especially when paired with a nice utility library like Ramda [1].

I tried to look into if native persistent data structures was on the roadmap for a later version of ECMAScript, but this random proposal on GitHub [2] was the only thing I could find, and I'm not familiar enough with the standardization process to be able to gauge how much traction that proposal is getting.

If anyone else is aware of similar efforts, I'd love to hear about them.

Until something like this makes it into JS proper, I'll be putting my weight behind ClojureScript.

[1] http://ramdajs.com/docs/

[2] https://github.com/sebmarkbage/ecmascript-immutable-data-str...

What has happened to Javascript is the same thing that happened to other fundamental high-level languages before them. It has changed from a high-level language to an assembly language just like C and Java.

Of course you canb choose to live in the past and keep on hand-rolling your Javascript just like others do with C and Java, but the world has changed. In today's world we write our code in a high-level language and have an optimizing compiler emit the assembly/machine code that our compute engine executes. The details are a bit different for different compute engines.

For C, the high-level compiler might use the same backend as the C compiler to emit machine code for x86 or ARM, but it will make integrating C libraries easy to do. For Java, the high=level compiler may emit Java class files directly but it will make integrating Java libraries easy to do. For Javascript you have Scala.JS and Clojurescript emitting optimized Javascript because the compute engine executes that directly.

As a developer it is worthwhile knowing all these low level details of internals because you will need to debug issues with that level of knowledge. But your main job should be to implement tested stable functionality for the users of your application. No matter how much you like C or Java or Javascript, it is always faster, more efficient and more reliable to write in a truly high-level language that incorporates the best knowledge of the latest research in Computer Science.

As a Javascript expert you may find that Clojure slows you down at first. That is the investment period. Then you start picking up the tempo, enter the payback period, and people start whispering about you being a rocket scientist or 10x developer.

Of course you could just stick woth Javascript but others who know how to roll with the punches will change with the times and win the 10X crown. Not because they are better, but because a true 10x developer is just a person who uses the best tools. They used to say that the suit makes the man. Nowadays it is the tools that make the 10X developer.

It has changed from a high-level language to an assembly language just like C and Java.

That hasn't happened to either C or Java.

> No matter how much you like C or Java or Javascript, it is always faster, more efficient and more reliable to write in a truly high-level language that incorporates the best knowledge of the latest research in Computer Science.

Latest research? Clojure is a Lisp family language, JS is an Algol family language. Both Lisp and Algol are from the sixties. Algol family is just more popular, so when people encounter Lisp family for the first time, they think it's "new".

> It has changed from a high-level language to an assembly language just like C and Java.

Neither C nor Java are assembly languages. What are you trying to express here?

> No matter how much you like C or Java or Javascript, it is always faster, more efficient and more reliable to write in a truly high-level language that incorporates the best knowledge of the latest research in Computer Science.

> always faster, more efficient > truly high-level > best knowledge > latest research

I uh.... what?

The author asks WHY hasn't clojure caught on if it is great.

I think I have a better answer than his conclusion that it aint popular because people shun things that aren't popular.

(1) coding when EVERYTHING is immutable by default is a royal pain in the arse.

(2) Coding directly in Abstract Syntax Trees is not pretty, there is a reason why most programming languages don't look like lisp.

> coding when EVERYTHING is immutable by default is a royal pain in the arse

Not sure I'd agree with that. Scala is a pain to write at times, but it's not because of the immutable data structures--indeed, the APIs are structured such that it's pretty painless. And while under the hood Kotlin's "immutable lists" aren't actually immutable (they're just ArrayLists, the interface is more akin to C#'s IReadOnlyList<T>), the API they present on top of it makes this pretty straightforward.

In both cases, you can do mutable things, but it's extra work.

I tend to think it's more of a Clojure-specific thing, and I think your #2 is more to the point: people don't use Clojure because it looks funny and is foreign to read for people who don't already know Lisps, that's all.

(I've used Clojure, but I don't claim to "know" Clojure. YMMV.)

I have a different theory about this. Most people are practical and don't like too much abstractions. So any language that lets you make abstractions, no matter how beautiful it is internally, and no matter how useful they can be in coding, such as Lisp, Forth, Scheme, Haskell, Clojure.. (you name it) will not be popular, sadly.

Weird thing is that functions are, for the most part, also a tool to make abstractions, but for some reason, the perception of them is different.

I came to this conclusion after discussions with people I know who don't like these languages, and I now think it comes down to this.

> (1) coding when EVERYTHING is immutable by default is a royal pain in the arse.

Is it really? Because I haven't noticed writing my Erlang.

> (2) Coding directly in Abstract Syntax Trees is not pretty, there is a reason why most programming languages don't look like lisp.

I think it is, but I'm biased :). Still, I don't think this is the reason. I believe it's simply because, due to accidents of history, C won the popularity contest, and most languages followed with (incrementally altered) C syntax to stay close to what's popular.

Coding in nearly the cleanest possible notation for abstract syntax trees is simply breathtaking.

The reason a lot of programing languages don't look like Lisp is that most programming languages don't have anything interesting semantically going on. Their authors' primary source of intellectual pride is the work that went into the syntax.

Part of it is CS education. It is drilled into the heads of CS undergraduates that programming language design involves tokenizing, and parsing with LALR(1) or what have you. The idea that you're going to have those pieces there if you design any language for any purpose is deeply ingrained, like the idea that no matter what you will be coding, you're going to have modules with functions that have local variables, and that there will be a edit-compile-debug cycle, and so on.

>Functional programming in JavaScript is an antipattern

The article then shows ClojureScript as an alternative.

In the comment section Ken Aguilar mentions two other alternatives: PureScript and Elm.

But there are more! Bloomberg's BuckleScript (which is OCaml; possible used on onjunction with Facebook's Reason), GHCJS (Haskell), are two other FP langs that compile to JS. These two have the added bonus of being strong langs for performant server-side programming as well.

http://www.purescript.org/

http://elm-lang.org/

https://github.com/BuckleScript/bucklescript

https://facebook.github.io/reason/

https://github.com/ghcjs/ghcjs

Elm is nice. Really really nice. It make it very intuitive and straightforward to write well architectured front end code. The compiler tells you straight away when something is wrong.

I have recently started playing with Bucklescript and am really loving it. There is bucklescript-tea which is a port of the Elm architecture to OCaml. So not only do you get the goodness from Elm - intuitively well architectured applications, but you can do it in a language that can be used everywhere - not just on the server.

Another worth mentioning is Typescript. Having discovered the joy of types through Elm and Bucklescript it was a real pain having to go back to maintain a fairly large javascript code base. My initial thought was to rewrite the whole thing in OCaml, but that would take months if not years. Instead I have started moving it across to Typescript. No code needs rewriting, I can just slowly one file at a time start adding typing information in. I have found a lot of subtle bugs and bugs I knew existed but was tearing my hair out about just easily presented themselves via compiler messages.

I will never go back to raw javascript again.

Curious question: Why did you choose Typescript over Flow? Flow's type system is better designed. Also, Flow's annotations are really optional, as in: Generating JS from Flow means throwing away the annotations. Nothing else, no code generation at all.
I struggled to get Flow working on FreeBSD. Typescript worked straight away, so I just went with it.
(comment deleted)
To all those who downvoted this question: Do you care to elaborate?
> Another worth mentioning is Typescript.

Sure it's worth all mentions (and so is Flow), but they do not specifically promote FP. And that's the topic of the article we're discussing :)

I've been doing FP in JavaScript fulltime for a few years now. I find it much easier than the OOP approach.

My advice to the author is: choose ImmutableJS, Ramda, OR lodash. Don't choose all three.

I think that is his anti-pattern.

> I could be more productive if I didn’t have to wonder things like ... “Should I mutate this variable?”

If you're doing FP the answer is likely 'No.'

Agree with this one. Reading article i though "Why don't you just drop ImmutableJS in favor of pure js collections with lodash/fp?". I felt the same when were using ImmutableJS. Two collection libraries across the app is very inconvenient. One could build entire infrastructure with ImmutableJS and restrict native collections to only system boundaries, but in js you usually befriend a lot of libs which makes it complex.
Or?

Ramda doesn't even have the same functionality as Lodash.

There is however enough overlap that using both ends up being a mess.
Excuse the overstatement -- there are sane ways to use the libraries in the same project. The point was the 3 libraries all prescribe a certain model of structuring and operating on data. One cannot reasonably expect to use all 3 without some cognitive overhead.
I see.

I was just reminded of last week, when I needed a utils lib. I read many good things about Ramda, but then I wanted to debounce a function and it failed me, haha.

Funny, but HN oldsters probably remember when functional programming wasn't at all tied to immutable data structures, and when Lisp and derivatives where considered enough functional programming, without every discussion of the topic requiring strictly requiring purity and immutability -- just first class functions, map, fold, and the like.
I was taught in university that functional programming means using functions as first-class-values, so function can get other function as a parameter. That's all. You can write functional code with assembler if you want. Immutability is just another design choice with its pros and cons.
Not sure why you're downvoted. That's literally the way I learned it first, too. Functional <=> "can use functions as values".
Functional programming is also a family resemblance thing: you can't necessarily give a strict definition, any more than you can define "blues music".

I'd say functional programming is a tradition that draws from sources like denotational semantics, lambda calculus, Church, Landin, etc etc.

There are some different subspecies of functional programming: the Lisp family that draws from AI engineering, MIT, Emacs, actor research via Scheme, etc; the ML family that draws from typed lambda calculus, inductive definitions, and logical proof systems; and more, like concatenative languages.

JavaScript was always inspired by functional programming, as evident by Eich's claim to have tried to sneak in a variant of Scheme dressed up as Java. I always use lots of anonymous functions, higher order functions, and nonmutating transformations in my JS, without using any special immutability libraries, and I'm pretty happy with it.

I've always thought that functional programming is about structuring your program in functions and their composition (as opposed to classes) - nothing to do with immutability either.

As for JS, I've read "Javascript: The good parts" one day and realized that I can do everything I want using just functions and closures - it's really elegant imo. (even use this approach in Python sometimes)

(comment deleted)
> using functions as first-class-values

This is called higher order functions (HOF).

FP is a --in my humble opinion-- broader topic describes a certain programming style. HOF is one thing in there, but so are "function+data rather then classes" and "favor immutability".

In contrast the imperative programming style is not merely about "not having HOF" or "mutable variables all over the place".

The immutability comes in with the definition of 'function', which, in some circles, means something more specific than an arbitrary unit of code that is callable and which may or may not return a value. While neither 'function' nor 'functional programming' can be used in computing with any precision unless they are qualified, there is a distinct paradigm in which functions have no side-effects and are the only mechanism of elaboration.
Mathematically a Function is a Relation that has two special properties: uniqueness and existence.

(these properties names can be wrong as I've not study calculus in English)

So on the machine, Immutability plays an important role on the first piece, uniqueness, so it tries to guarantee that results are not just "equal objects, but different instances", which breaks the function definition.

Of course that functions that return a new object for the same arguments, even if it's immutable, are not true math functions.

Mathematical functions aren't too great a metaphor for computer functions. They share a lot of similarities—domain, range, inputs, outputs, composability. But mathematical functions just are, there's no notion of changing things—however, the most common purpose of computer software is to change things. So it breaks down, or you come up with some way of defining a change without anything changing, which adds a layer of abstraction to everything you try and do.
I think it is correct to say that, in the functional paradigm, you effect change by making something new (and forgetting some older things.) Regardless of the paradigm (other than self-modifying code, perhaps) programs just are, but they must be evaluated if they are to do something useful.

I will leave that last sentence as I wrote it, but it immediately leads me to wonder if functions that write functions have wandered into the self-modifying code realm?

I really agree with you. Think that there's a tension between how a computer works and how a functions operate on data.

Immutability and Referential Transparency help reduce that friction, but in the end we still have not found a real solution. That's why languages like Haskell require a bunch of gymnastics just to allow IO to be seen as pure functions.

I think the reason is rise in CPU power - immutability has a processing cost, but it makes things easier for programmers. This is a general trend in programming languages over decades - higher abstraction (easier for programmers) but harder for compilers to optimize.

For example, Common Lisp has two versions of list functions that modify list - one that returns a copy and another that returns mutated original list. (By the way, Paul Graham in his On Lisp, which is from 1993, mentions that functional programming style means that function doesn't modify its arguments and rather returns a copy.) Because once upon a time, the difference actually mattered. Today, mostly it doesn't.

Common Lisp has all this stuff because it comes from a tradition of writing efficient code in Lisp itself, where code can be anything from a file system, network stack, theorem prover, graphics toolkit, to itself ... It is already its own implementation language where a programmer might want to control some aspects of memory allocation.

Other languages delegate this stuff to the implementation language/runtime, for example Java/JVM.

Agreed--being able to define functions for control flow & data transformation seemed functional enough (compared to having to rely on primitive reserved words).

Of course, even then, C was functional by that definition (as long as you could remember where the parens & asterisk went when defining your function!)...so what do I know.

On the other hand, if you have the attention span and interest, Li Haoyi has an interesting (and, in its conclusion, useful) take on this topic:

http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbo...

Language is a tool for communication, and the great strength of English is that it is defined by consensus. Words shift in meaning.
Which is neither here nor there regarding my original observation, which didn't deny that "words shift in meaning" but called to attention (or to memory) a particular shift in meaning.

That said, and being a pedant, I must say that while English (or any language) does indeed change, it doesn't do so by any kind of consensus. People don't stop and give consent to a change in meanings, they roll along with it. There are some mechanisms in this shifting of meanings (needs to describe new concepts, fashion, immigration, etc) but consensus is not one of them.

Oh, come off it. Yes, you carefully phrased it so that your post isn't explicitly criticism, but it's clearly implied.
Yeah, and---literally, not to be snarky---times change.

FP isn't a technical definition. It's a cultural, family-resemblance definition that's driven by some mixture of fashion and genuine exploration into a niche of ideas in computing and formal languages.

The best you could hope for would be a set of shared values of the FP culture and then justifications for why various things that call themselves FP feel that are upholding those values. Even with a definition like this though, the values will shift and waver over time.

Here's my FP values:

    * Simple over easy.

      Rich Hickey's old egg. Favor abstractions with few moving parts,
      reduced interactions, and more parsimonious overall models over
      ones driven by metaphor or target use case alone. Result is 
      tools which are perhaps harder to get started using but have
      better complexity scaling properties.

    * Mathematics has been doing this a long time.

      PLs are just formal languages and mathematicians have been working
      seriously on formal languages for at least 150 years: steal their
      ideas. From this we get ideas around comparative linguistics, 
      semantics, various proof/reasoning mechanisms and types.

    * Readability counts, but not just in the sense of syntax.

      Really this means "legibility" or even "static legibility". It's 
      another hint toward types, immutability, and general state space
      reduction. It's a strong push away from "emergent behavior" to the
      greatest degree possible. Things should endeavor to do what they
      say on the tin... and to to the greatest degree reasonable say things
      on the tin in such a way that the information is available from the get-go.

    * Tradeoffs between power-to-construct and power-to-analyze.

      This is everywhere in formal languages/PL, but it's especially strong
      in FP since there's a focus on (simple over easy) semantics. It opens
      the door for there to be mathematical semantics as opposed to just
      operational semantics and this makes for rich opportunities for on-the-tin
      static reasoning (equational reasoning, changing interpreters, embedded DSLs).
 
I think these values more or less were in place back in the old Lisp-y FP days, but they really are taken to new places by "more modern" takes on FP.
The book "Functional Programming" by Field and Harrison (1988) was already very much into referential transparency as the panacea for all our programming woes:-)
Not well reasoned. Mostly of the complaints boil down to 'not knowing' whether a given piece of data is mutable or not.

If you're doing FP with immutable data, there is no ambiguity: you never mutate. Doesn't matter which language you're in, nor whether the data-structure is mutable or not (e.g Redux mostly uses normal mutable JS objects, with the spread operator to avoid mutation when returning a new state).

I think the biggest weakness in the ecosystem is that it's cumbersome to map between different approaches to immutability. I'd like to be able to use clojurescript for some stuff, reason/bucklescript for other stuff, and immutable.js for still other stuff without having to jump through hoops when passing immutable data around.

Are there immutability constructs in flow or typescript that would allow libraries to conform to a type interface for conversion?

I hate the arrogance of announcing that thousands of developers' work is an antipattern. This post contains valid discussion of some of the shortcomings of FP-in-JS, and presents alternatives. That's fine. But everyone has their own priorities and tradeoffs. The downsides of adopting Clojurescript in my current situation would outweigh the benefits.

> Clojure compiles to Javascript... So any Javascript job could be a Clojurescript job

That's not how it works.

Maybe it's arrogant to call out valid criticism as attacking the work of others, rather than just the paradigm.
Why ClojureScript and not PureScript?
One of the most annoying JS FP antipatterns is when people use fancy 3rd-party currying when a simple ES6 fat-arrow would suffice.

"_.curry(f,0)" instead of "x => f(0,x)"

Don't use a weakly typed language use instead my dynamically typed language!
Don't use immutability in JS. Though, use Ramda, since it's much better than plain JS.

This, then, would solve almost all of the problems mentioned in the article, yet remain functional friendly.

Ramda functions never mutate the object by always returning a new object, this is very simple to reason about, and it's pretty close to immutable programming without the overhead yet only one API.

Just a note on immutability, I feel like this is pretty straightforward in ES6 (map, spread operator, and Object.assign) and will be more so with spread-operator for objects in ES7. Am I missing something?

I mean, you still have to THINK about whether you need to keep something immutable or not, but that's the difference between a junior developer and a more seasoned engineer, right?

This is the C++ trap - you keep piling on more features to the language and then you can answer some criticisms by saying "just use this subset". But this is not how the usage of programming languages pans out. Programmers can't agree even with themselves (=consistency) about what subset to use, or have accidents with it. And libraries / practices in that PL's culture can't rely on those conventions and subsets, so they can't really leverage the benefits. It's basically inventing your own mini-language with borders drawn in the sand and not enforced by any tooling.