But, in the case of JS, there's one major practical constraints: Introducing a new language must not regress performance of JS. (Why? There's an absolute ton of JS on the web. Getting 1% of the web using a new language able to be quicker doesn't matter if you regress 99% of the web.)
You may think, "Sure, that's easy. You just add a second VM, entirely disjoint from JS!". Unfortunately, it's not that easy: if you allow the languages to coexist in the same page, you then need to GC across both languages (as some objects are shared between the two runtimes, primarily those relating to the DOM), and cross-VM GC is an active research area, where nothing has been shown without at least a 10% performance hit to both GC impls.
Well, then, how about having a "generic" VM that runs JS within it? You're going to have an uphill battle to get performance equal to current JS VMs, because their bytecode (ignoring V8 for now!) encodes a lot of high-level semantics of JS, which means any new language, to have good performance, would have to share a lot of semantics with JS. This inevitably puts massive limitations on what any new language can be like, and restricts it to being "JS-esque".
So what can we do? There are two basic options: subset JS, though inevitably this doesn't sort out things like `==` v. `===`, but you can get to something where you can statically check you're using a sane subset (e.g., not using `==`, not using any undefined variables, etc.); or, write some language not overly dissimilar to JS and compile down to JS (the "not overly dissimilar" restriction is a practical necessity as you can't really afford to send large language runtimes and standard libraries over the wire). In both cases, JS is ultimately the target thus it's important to keep on fixing what can be fixed with JS (e.g., the lack of a module system, the lack of memory-efficient data structures), but both can improve the situation over unrestricted JS as it is today.