Leaving Python for JavaScript
hire.jonasgalvez.com.br
hire.jonasgalvez.com.br
Look, writing programs that respond to HTTP requests with HTML is not rocket science. You can do it in JS, Python or Ruby and be very productive. If you hate yourself, you can do it in Java, Go or whatever else and trade server performance for development speed. If you really hate yourself (or are Amazon circa 2004), you can write your whole website as a C++ static binary.
My theory is that the endless proliferation of JS libraries, frameworks and language revisions are because lots of smart and talented developers are employed to build websites - but building websites is just not that technically interesting, so they express their creativity by creating new tools, frameworks, package managers and ES revisions. It's a symptom of boredom.
But my one bit of career advice would be don't "Leave X for Y." Don't tie your livelihood and career to a single X or Y. Learn how to use a variety of tools and pick the best one for each job. Any big project will require using a few different tools and really valuable developers are the ones who can navigate that entire landscape intelligently.
As for boredom, though, it's true, but every now and then something special emerges out of boredom, as was the case for Vue.js and most recently, Nuxt.js for me.
I hate the amount of JS frameworks and libraries available like everybody else and if anything, this article is also a short reference for myself in disguise on _how to get started_. I'll say though, knowing your way around a Node.js project can be painful, but with a little experience can become really reassuring. Code runs fast, it's easy to write (easy idioms to memorize like Python) and is generally very predictable.
I mean look at this:
dotenv (lets you load the environment from an .env file), axios
(HTTP client library), cheerio (HTML parsing library), bcrypt
(password hashing), co-body (HTTP body parser), co-busboy (HTTP
multipart parser), jsonwebtoken (JWT generator), koa-jwt (JWT
middleware), koa-router, koa-sslify, vue-no-ssr and source-map.
What the hell is all that? I am not saying he is wrong... I am just saying that I don't have the capacity to play in that playground. I am also asking if any of those libraries will be around in a year?Just start somewhere; and in a month or two, you would mostly know which libraries you need to add to your project.
The best way to go about it, is to check a few popular open source projects; what libraries they typically use.
> I am also asking if any of those libraries will be around in a year?
You can check the download stats of these in https://npmjs.com, and activity on the GitHub repo, before adding it to your project.
If they are still around, but have published a new major version to update a few APIs; you can slowly migrate to it.
If not, you'd read some Medium post or Hackernews discussion, about what is replacing that.
There's something called Greenkeeper (https://greenkeeper.io/) that integrates a GitHub bot to your repo, and files a PR when something needs to be upgraded.
You can implement something similar on your own, if you aren't interested in using something like this.
A materials engineer simply cannot afford to pick concrete unless she knows the specific load and weathering characteristics of it. The same should be true for software projects. You shouldn't use cheerio because everyone uses it in their project, but because you've looked through the source and considered all your options for need it fills.
Sorry for the rant, but I think it's important to encourage software developers to think before they code.
As an outsider the big amount of dependencies look daunting, but the tendency in JavaScript as of late has been to use small libraries that do one thing, do it well, and play well together with others (Composable is the buzzword). Whereas Java and C# for instance tend to have macro libs that "Have it all bundled in".
It's different approaches, and you might not _need_ absolutely everything, then again you might, and you are in a much worse position to evaluate that as an outsider than the developer who made it.
All in all, I quite like the JavaScript approach where pieces are just that, instead of a pre-built lego set which I'll have to study to build, I have small pieces which give me more flexibility to take my project where I want to take it. The tradeoff, and they naturally exist, is that dependency maintenance is substantially more difficult, and the likelihood of something you use being straight up abandoned raises for each dependency you add. Which might lead to having you either maintain that piece yourself, or abandon it, and add another piece that fulfills a similar role.
Libraries of code.
> I am not saying he is wrong...
Good, because they are right.
> I am just saying that I don't have the capacity to play in that playground
Good, because you are right.
> I am also asking if any of those libraries will be around in a year?
Yes. Some have been around for years already.
Listen, it's fine that you are using Python. It's fine that the OP is using JavaScript. It doesn't make you wrong. It doesn't make them wrong. Just because you are confused doesn't make it wrong. Hell, Python should worry about itself; it has enough warts of it's own it doesn't need people pretending that a library like bcrypt is confusing.
Do you see ancient but popular PHP frameworks going unmaintained and reach the point where they collect a significant amount of bugs and vulnerabilities? Not really...
There are sentences which are telling a huge incompetence about the person using these.
This sounds the same story to me as "We used tech X, but X is shit/can't do something so we switched to Y, and Y is awesome and fast." Where the person switching was just incompetent with X but it would have been perfectly solvable and they just do a totally different thing with Y.
In the specific "passing a function" case, yes, it's impossible to pass only a function body, but I think it's impossible to do in JavaScript also? (correct me if I'm wrong), because you pass in function. You can do the same in Python by defining a function in the same scope and passing that in. If you don't like that, it's just one opinion, not necessarily good or bad. For example, I find it ugly and difficult to handle nesting this multiple times (defining another anonymous function inside an anonymous function) which is called "callback hell" if I understand right, but that's just my opinion also, because people seem to able to accept this hell. :)
let doubled = nums.map(x => x * 2)
and this: def double(x):
return x * 2
doubled = map(double, nums)
(my Python is pretty rusty so maybe there's a better way of doing that) doubled = map(lambda x: x * 2, nums)
JS it's just not as explicit with what you're exactly doing. def foo():
# ... four lines here ...
modified = map(foo, items)For example, `f` is a refactoring of an anonymous function:
function f (item) {
return {
// foo properties
}
}
const fooItems = values.map(item => f)
Imagine that you have to map over several different collections of items, and generating the lists `foo`, `bar`, and `baz`. You have to either name the functions we pass to map `f`, `g`, and `h` (which I bet our reviewers would hate), or `fooMapFunc`, `barMapFunc`, `bazMapFunc`. It just pollutes the namespace that I have to keep in my head, because I have to wonder "is this used somewhere else?".Moreover, is it _more readable_ to define the helpers first, and then the collections that are made by using them, or to define the pairs (fooMapFunc, fooItems) in sequence? This could easily be felt one way or the other, and both are valid, but leads to code review holy wars. "I feel this is more readable / I feel exactly opposite".
For comparison, the anonymous version of this similar operation:
const fooItems = values.map((item) => {
return {
// foo properties
}
})
const barItems = values.map((item) => {
return {
// bar properties
}
})
const bazItems = values.map((item) => {
return {
// baz properties
}
})
In this case, the anonymous function is clearly not usable anywhere else, so it's easier to be sure that it's something one can change, and completely removes the chance of holy war over readability of whether to define helper functions together or with their collection.A nested function is a simple abstraction in a narrow scope. Both the abstraction and the name are easy to change, so the name only has to describe what the function does now. When that's hard, it's often because the function does too much, does too little, or belongs somewhere else. Likewise, people arguing about the organization of inner functions is usually a sign the outer function should be refactored. Anonymous functions are appropriate when names would be almost redundant, not when coming up with a name is hard.
My editor can show me where a function is used; it can't summarize what a function does. Either way, you have to find where "fooItems" is used to know if you can modify the function.
Conversion functions are very easy to name ("itemToFoo"). Idiomatic Python would just use a loop:
foo_items = []
for item in values:
foo_items.append({
# foo properties
}) return [x*2 for x in nums] doubled = [x * 2 for x in nums]Typically in programming you don't often encounter the need to pass a multiline anonymous function into another function, it leads to confusing code. Async/await gets rid of this bs all together which is the pythonic way to do async.
btw pythonic code for maps or filters is to use list comprehensions so
doubled = [x2 for x in nums]
or if you want to use a anon function:
doubled = [(lambda y: y2)(x) for x in nums]
In my experience (I write mostly JS but also a lot of C# and, not as much, Rust), passing functions around is very easy to read and reason about. Functional programming "Just Makes Sense™" to me. I think it's just an exposure thing. Many people find Python's significant whitespace cleaner. I disagree but I promise you it's because I haven't spend much time with it. If I wrote a lot more Python, I'd probably grow to like it.
>I'd say that anyone who's complaining about callback hell isn't up-to-date with the JS world. Promises have fixed this problem and, as you pointed out, async/await make it even nicer.
The latest node api still uses callbacks. Promises haven't fixed this problem, it's just a bandaid on stab wound. Async/await is the proper way to deal with this problem and python supports it so there's no upside for node in this area.
This is a synchronous callback (but callback nonetheless), that takes an array of numbers, and adds its entries:
arr.reduce(function(acc, item){ return acc + item; });
There's some boilerplate in this, so as per latest JS specs, you can remove all that and rewrite it as:
arr.reduce( (x, y) => x + y);
Then there's asynchronous callback. Most of "callback-hell" stems from these type of callbacks, because you would do "do-this-then-do-this-then-the-other-thing", and nest these one within other.
We realized that callback-hell prevents us from using return or handle errors in a clean & reliable way, so we went to promises.
Then promises turned out to be quite a pain too. Then generators, and now we have settled for async-await.
But in no way that "hell" is acceptable!
You can build really complex dynamic async chains in JS very easily because of this. It's hard to explain why it's so nice until you try it.
In JS, I can do something like:
Promise.resolve().then(() => {
let innerPromiseChain = serialOperation1()
.then(serialOperation2);
if (somethingIsTrue) {
// Only inject serialOperation3 at the end of the
// innerPromiseChain if somethingIsTrue
return innerPromiseChain.then(serialOperation3);
}
// else return the inner chain without serialOperation3
return innerPromiseChain;
})
.then((resultOfLastSerialOperation) => { // resultOfLastSerialOperation could be the result of
// either serialOperation2 or serialOperation3 depending
// on the value of somethingIsTrue
// parallelOperation1 and parallelOperation2 will be
// executed in parallel.
return Promise.all(parallelOperation1(), parallelOperation2());
})
.then((parallelOp1Result, parallelOp2Result) => { // This will be called once the previous parallel
// operations have both finished (therefore the
// whole chain has been processed).
});For imperative code the goal is to write code that is just as clear as writing a single threaded algorithm: a simple list of steps. Promises and callbacks DO NOT ACHIEVE THIS GOAL.
That stackoverflow post showed a python solution that's infinitely cleaner than js. Python skipped callbacks and promise chains and jumped directly to the best way to do async operations... async/await.
You want to shove a parallel set in an async chain of operations? Here's the way to do serial and parallel async operations in Python:
async def main():
# run them sequentially (but the loop can do other stuff in the meanwhile)
body1 = await get_body('http://httpbin.org/ip')
print body1
body2 = await get_body('http://httpbin.org/user-agent')
print body2
# run them in parallel
task1 = get_body('http://httpbin.org/ip')
task2 = get_body('http://httpbin.org/user-agent')
for body in await asyncio.gather(task1, task2):
print(body)
You see that code? Way more clearer way more understandable than your promise chain. Python has it's problems but your promise code is not powerful at all, it leads to over complicated code and just slightly better than callbacks.You can do pretty much exactly the same with JS but I do think that there is some merit to this intermediate step of having the then() clauses for backwards-compatibility because you can't always guarantee that the caller will in be an async function.
Async/await is an all-or-nothing improvement not an incremental one.
You can pass a function as a callback or something else in python. You just give the function a name then pass it. No function literals.
Also he's talking about async/await in koa... does this fool realize that async/await is built into python?
I'm proficient in both python and js and I have to tell you, python is light years ahead of js in terms of language design.
Sounds like you're more pissed off at the article because it contradicts your views than anything else. Sounds like you didn't even pay full attention to it.
Yes, those who assumed I meant you can't pass an anonymous multi-line function to another were obviously right -- it dazzles me people spent so much time arguing over this point. There's not much else to it.
I'll just say: that's definitely NOT the sole reason -- I point out several other factors that weighed in my decision in making JS my #1 choice. Above all, after seeing a few successful large projects deployed (and no issues in production), I just came to trust the Node.js stability and ecosystem.
JS:
doThing(function(){
blah();
de();
blah();
});
Python: def thing_doer():
blah()
de()
blah()
doThing(thing_doer)This confuses me quite a bit, there are nuanced differences between these ideas in the two languages but at the surface these are things that very much exist in both languages
arrow functions:
(x,y) => { x + y }
vs. lambda x,y: x + y
method shorthand definition: MyObj = {
foo(x,y) { return x + y }
bar(x,y) { return x * y }
}
vs. class MyObj:
foo(self, x, y): return x + y
bar(self, x, y): return x * y
spread operator: function add(x,y) {
return x + y
}
add(...[1,2])
vs. def add(x, y):
x + y
add(*[1,2])
destructuring: [a, b, ...rest] = [10, 20, 30, 40, 50];
vs. a, b, *rest = [10, 20, 30, 40, 50]
functional array methods: forEach(["Wampeter", "Foma", "Granfalloon"], print);
vs. list(map(print, ["Wampeter", "Foma", "Granfalloon"]))
async methods: function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function add1(x) {
var a = resolveAfter2Seconds(20);
var b = resolveAfter2Seconds(30);
return x + await a + await b;
}
add1(10).then(v => {
console.log(v); // prints 60 after 2 seconds.
});
vs. async def resolve_after_2_seconds(x):
await asyncio.sleep(2)
return x
async def add1(x):
a = resolve_after_2_seconds(20)
b = resolve_after_2_seconds(30)
return x + await a + await b
loop = asyncio.get_event_loop()
loop.run_until_complete(add1(10))
There's a lot of fun differences between the origins of these features and how they work but the sentence to me doesn't quite to the idea of "Leaving Python for JavaScript" justiceI find it refreshingly different.
I'm probably being overly optimistic, but I look forward to a future where a "naked JS" movement rises up, similar to "vanilla JS", but rebelling against tooling complexity instead of jQuery bloat, in which your website's /js/ folder contains pretty much exactly what's in git.
What. Why would you ever want a function body as a string? What kind of vile sorcery are you doing? One can use inspect.getsourcelines in python if really pressed to, but I find it horrifying that javascript developers actually seem to require this functionality often.
I tend to agree with the Python philosophy, that it's usually better to extract and name a function that to declare it inline. The `asyncio` module and `await` keywords go a long way in eliminating most use cases where I'd still prefer an anonymous function, for arbitrary callbacks.
You mean these critics find
>>> map(lambda x: x**2, filter(lambda x: not x % 2, range(11)))
preferable to the "fragmented": def square(x):
return x ** 2
def is_even(x):
return not x % 2
>>> (square(x) for x in range(11) if is_even(x))
Both result in the same lazy iteration (to see results below - requires materialization with a constructor like list or tuple), but I find the "fragmented" approach much more readable (so long as the functions do what their name says they do - I have seen Python where they actually did the opposite...) >>> list((square(x) for x in range(11) if is_even(x)))
[0, 4, 16, 36, 64, 100]
>>> list(map(lambda x: x**2, filter(lambda x: not x % 2, range(11))))
[0, 4, 16, 36, 64, 100]In the real world you filter water to get the water. In most programming languages filter() is more like a strainer or colander.
My guess is you ran into someone stubbornly insisting on the meaning of the word filter despite all evidence.
# square even numbers
range(11)
.filter(lambda x: not x % 2)
.map(lambda x: x ** 2)
However such a chaining API is not practical in python, because lambda syntax is voluntarily crippled to one expression only.For example I often end up doing:
something(
"Template string {thing}"
.format(thing=33)
) label = "Template string {thing}".format(thing=33)
something(label)Storing each step in variables has the advantage to be self-documenting and nicer when debugging. However in many cases I feel like wasting energy trying to find short and adequate variable names for each steps in a computation, especially when the steps are clear enough by themselves but difficult to describe in 1-2 short words.
You also need to keep the variable names in sync when refactoring, which may cause even more refactoring if the line gets too long with the new name.
IMO it makes sense to use both styles where they feel most adequate.
Can't say what python lacked except being able use same language on front end and back end. Except if he still uses python 2 which hasn't any new features in years.
@connect(...)
function StateLessComponent(props) {
}I think what is more important than the language it self, is the toolings and standard library.
every now and then you hear about a new framework, a lot of hype, which is not for big projects.
I think the wise thing is to move to golang
In language that pythonistas would grok:
Arrow functions: multiline lambda definitions
method shorthand definition syntax: class defined with only classmethods, or in other words a namespace
the spread operator: *args in functions
destructuring assignments: tuple unpacking... But also for creation of instances
all functional Array methods and async functions: functools and async... Plus a bit more
While most of this is good to know, I'd still stick with python for readability and maintainability purposes.
And to be clear, I would classify, say, Rust as not having many arbitrary restrictions. All the limitations that Rust has compared to C fit clearly within the language's core design. On the other hand, I don't see this same structure and consistency to some of Python's rules.
In Python’s specific case, I've seen no alternative that isn't bad for readability; the strong line-orientation of Python's broader syntax limits the good options for inline anonymous functions.
That being said complex lambdas in general can be adverse to maintainability and Python’s single-expression limitation largely prevents that (though you can make hideously complex opaque single-expression lambdas if you try.)
Vue is a great language but php can offer more in the backend
Seriously, professionality is being able to use the right tool for the job at hand.
How?
JS:
var args = [0, 1, 2];
myFunction(...args);
Python: args = [0, 1, 2]
myFunctions(*args)
A more complicated one:JS:
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
Python: args = [0, 1]
myFunction(-1, *args, 2, *[3])
As used in list building; JS: var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
Python: parts = ['shoulders', 'knees']
lyrics = ['head', *parts, 'and', 'toes']
"A better way to concatenate arrays"; JS: var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
Python: arr1 = [0, 1, 2]
arr2 = [3, 4, 5]
arr1 = arr1 + arr2
(Though the star notation works here too.)I omit JS's use of ... on objects; Python's class system works differently — and IMO, more rigorously — than JS's, making ... less sensible on Python objects. (Python focuses much less on passing around untyped key-value bags and more on strongly typed classes IMO; both are possible in both languages, but the idioms around them differ, and I think Python's idioms tend more towards having a well defined class with well defined attributes, and not having just a bag of attributes, moreso than JS at least, and I feel that direction (well defined classes) leads to more robust code. In particular, it forces you into naming your concepts, and defining their set of attributes: a simplistic type definition.)
> all functional Array methods
Python has map, reduce, etc., as well as generator and list comprehensions which are often easier to use.
> async functions
Python and JavaScript have practically identical syntax in this area.
> there's no acceptable way to pass a function body to another in Python
I find it very acceptable that if your function body is more complicated than an expression, that you're forced to pull it out and name it, frankly. I think it does good things for fighting complexity, and this just isn't something I worry about day to day while using Python. But I will concede that Python does lack a syntax for passing a function in an expression context.
(But I would also note JS's screwed up named-function syntax; in Python:
def foo():
# body
is a valid statement. JS's: function foo() {
// body
}
is not a valid statement, and can only appear in certain, particular contexts. In particular, the following is not valid JavaScript, though many implementations will do The Right Thing™, I'm told: if(true) {
function foo() {
// body.
}
}
[2])> My code usually revolves around higher order functions, reduce(), map(), etc. I can't remember the last time I wrote a regular for loop in JavaScript.
Because JS for a long time (until ES6's for(… of …) syntax) lacked a for loop (the C style look, and for(… in …), do not count, as they do semantically different things), which is why you're using forEach().
> arrow functions
The best thing about arrow functions is the sane binding of `this`, a problem notably absent in Python to begin with.
> [Python's] class definition boilerplate is still hard to look at
This is sometimes true; I find the attrs[1] package helps greatly here for small, struct-like classes.
Posting short inflammatory comments isn't going to change how people approach the topic.
Your blog is extremely difficult to read on wide screen monitors. The entire left 50% is basically just blank space. My suggestion is to make the left side maybe 20% width on desktop or less.
Also, regarding the article content:
There really aren't any good reasons presented here about why you moved from Python to Javascript for back-end web development. It seems that you simply prefer Javascript semantics. There's nothing wrong with that, but the title is misleading considering that the bulk of the article is actually about which JS tools you use on recent projects and not why you moved.
Also, could you clarify what you mean by
> Also, there's no acceptable way to pass a function body to another in Python.
Functions are first-class in python and can be passed as arguments to other functions. I'm not sure I understand what you mean with the above statement.
Cool to see someone else has been using Nuxt though.
I believe the author is referring to inline definition:
setTimeout(function(){alert("Timed out!");}, 5000)
You can do something similar with lambdas in Python, but the allowed syntax is relatively limited compared to a full function definition. You could also define an inline function, but it'd be in a separate statement from the call you make with it. Unfortunately Python doesn't allow for creating and returning a first-class function in a single expression.There is no way to do write this in Python:
someFunc( _ => {
// this is
// a function
// with multiple lines
})
Having to define a named function to use it as a callback is a pain in the ass.Python has an excellent standard library but the language itself is pretty mediocre IMHO. Classes are an afterthought thus verboses, as so is "functional programming" in Python.
JS biggest issue is that it is not strongly typed enough. But ES2015 makes it really pleasant to use.
if you have a multiline function it should be named and unit-tested instead of just stuffed anonymously into some pyramid of doom
It's like saying all data should be declared as variable, in the functional programming paradigm, functions are data. That's why closures are useful. And it has absolutely nothing to do with unit-testing, that's beside the point. Javascript is not harder to unit test because it has fully featured anonymous functions.
It is if you actually use them. ;)
> It's like saying all data should be declared as variable, in the functional programming paradigm, functions are data. That's why closures are useful.
I don't think you understand what you're talking about. We were already talking about using 'functions as data', and closures and anonymous functions aren't the same thing.
But anyway, how do you unit test an anonymous function?
I assume you mean that you don't, you just test the bigger context around it. But that was my point, once your anonymous function starts becoming much bigger than a one-liner it ought to be tested itself.
Happy debugging!
Typing
someFunc( _ => {
// this is
// a function
// with multiple lines
})
Is only one line shorter than def foo ():
// this is
// a function
// with multiple lines
someFunc(foo)
There is a case to be made that the second version is more legible and that exposing the function foo makes unit testing it possible. I can understand why people might slightly prefer one or the other, but I honestly can't understand the intensity of opinion around this seemingly very minor syntactic difference.I'm curious what you find verbose about Python classes as:
class FooBar():
text = "Hello World!"
def hello(self):
return self.text
feels fairly terse to me. def __init__(self, foo)
self.foo = foo
There is an attrs package and new proposal (https://github.com/ericvsmith/dataclasses/blob/master/pep-xx...) to remedy that. class Foo:
bar = 42
def __init__(self, **kwargs):
self.__dict__.update(**kwargs)
But I agree that's not a super robust solutionThanks, I'll take a look when I have a chance. I myself don't own a widescreen monitor, the site looks fine on my MacBook and several other computers. It's not a paid job, not a lot of effort went into it ;)
> but the title is misleading considering that the bulk of the article is actually about which JS tools you use on recent projects and not why you moved.
Hm, actually, it's not. I'm surprised by this comment. I point out precisely the JavaScript features that weighed the most in my decision: "So with JavaScript you've got arrow functions, the method shorthand definition syntax, the spread operator, destructuring assignments, all functional Array methods and async functions. Combined with Vue's minimal patterns and Nuxt's conventions, I can't think of a better language to write web applications in."
> Also, could you clarify what you mean by > > Also, there's no acceptable way to pass a function body to another in Python.
Exactly that, a "function body", "closure", "inline function", whatever you wanna call it. In Python there are lambdas, but they're limited and not even encouraged anymore. We're left with passing function references, and that's where JavaScript comes out the winner IMHO.
I do admit that Javascript's object and array destructuring is extremely nice. The combination of destructuring and the spread operator makes working with heavily nested JSON much more enjoyable than in Python.
IMHO, complex/nested anonymous functions are usually bad for maintainability, so I'd rather have a language that doesn't allow them (Python) than a community that overuses them (JavaScript).
I saw that. I guess I just expected you to go into detail about why you believe things like that are better. I use JS a lot in my day-to-day work for the front end of my web application. I also use Django and Python for my back-end. I'm well aware of the differences between Python and Javascript as they are the two languages I work with the most. I would not consider either language "better" than the other except at specific tasks. i.e. I can't really use python to build an SPA and it would be a pain to use Javascript for anything involving heavy number manipulation. I guess what I'm saying is that you should always choose the right tool for the job; sometimes that will Python and sometimes it will be JS. Other times, it might be something else. I'm always a little confused when someone decides that they're going to start writing everything in a particular language even when other languages are more suitable for the task.
> Exactly that, a "function body", "closure", "inline function", whatever you wanna call it. In Python there are lambdas, but they're limited and not even encouraged anymore. We're left with passing function references, and that's where JavaScript comes out the winner IMHO.
To each their own I guess. I feel like programmers these days automatically assume that more functional == more good. There are cases where using FP techniques is definitely advantageous. However, there are also circumstances where OOP is a better choice. I find that Python is equally capable of both paradigms. The idea of anonymous callbacks is good from a productivity standpoint, but readability suffers. Anonymous functions in general cause cryptic error messages and are difficult to debug. I've found that the over use of anonymous functions can also lead to a lot of duplicate code. There are many cases when an anonymous callback would be better if refactored into a named function. I believe that having more named functions aids in creating an efficient program compostion, even when using the FP paradigm. There is one use case where Javscript is much better suited than Python: web applications front ends. This comes as no surprise as JS was designed for exactly that purpose. Asynchronous callbacks and promises cannot be beat when dealing with fetching data from an API.
Then don't use them. The javascript ecosystem on the backend and frontend has settled down quite a bit. Use something that's been established for a while (React, Vue on frontend or Express, Koa on backend) and you're not gonna suffer from churn too badly.