Some of this is a lack of familiarity. You wouldn't dream of using C without reading a book first. You wouldn't dream of tackling a Java project without reading on the topic. You wouldn't even dream of trying something as simple as Python without a bunch of reading.
Why do you try to code JS without reading about the language? It's the only language where people consistently try this kind of thing.
> false != x
Referential equality operator is `!==` (which isn't so different from lisp where you have eq, eql, equal, string=, etc). Fun fact: Eich didn't have type coersion in the language at first. It was added at the insistence of developers (something he regrets, but Microsoft forced this to stay in the spec)
> function () {
switch (WTF) {
}
}();
A lot of languages don't make switch statements into expressions. The fact that JS can do this via a function while most other popular languages cannot do it at all is a benefit if anything (there is a proposal to allow these to be expressions). More generally, prefer this
let foo
switch (abc) {
case "blah":
foo = 123
break;
}
> the switch statement has the idiotic break with fallthrough found in C.
It actually gets this from Java. Eich was told to make the language look like Java and he did.
> dict[key] = (dict[key] || 0) + 1;
Your code is potentially bad. `||` uses "falsey" values. If the key is zero, the left-hand side will return false forcing the right-hand side. Use `dict[key] ?? 0` instead as it will only return the right-hand side if the left side is `undefined` or `null`.
If it is a pure dictionary, you are using the wrong construct too. Use `Map` instead
let dict = new Map()
dict.set((dict.get(key) ?? 0) + 1)
> this calls for two dictionary key lookups. You want this sort of thing in a single operation.
You get a value rather than a reference. I believe the JIT can optimize this pattern. If you are really fixated on using a reference, store an object with a value instead so you can grab and keep an object reference.
> What is "function scope" and why even have something so idiotic?
In lisp, you'd use `(let ((foo 123)) (print foo))` to set an explicit scope. ES4 proposal had a let block which I think would have been a better idea than the current stuff. Function hoisting generally occurs in other languages one way or another, but is hidden from the user.
> for (let i = 0, j = 0; ....
Yep, this is one more reason why the correct fix was a let block with `let (i=0, j=0) for (; ...)` or 1et for (var i=0, j=0...`
> Appending together Lists has functional semantics, like Lisp:
Array.prototype.concat goes back to at least the ES3 spec as does Array.prototype.push. At the time, arrays were either implemented as hashtables or linked lists. My guess is that adding a single entry to the hashtable only occasionally caused a resize while concatenating N lists was almost guaranteed to do so. I think they decided that it was easier for implementors to just create a new reference.
Since ES5, most new array APIs have favored returning new lists for everything. I think there's a case for making new versions of those older APIs that behave immutably.
> if (foo.bar.indexOf[key] This could happen in any language with a methodNotFound handler. For what it's worth, `if (foo.bar.contains(key)) {code}` would be the better way of writing it. I think Typescript would also catch this (though I'm not 100% as I don't remember ever having made that particular mistake).
> Every damned object is a dictionary with properties you can access as strings with square bracket indexing, and that is always safe: it yields undefined if the property is not found.
Garbage In; Garbage Out. At least it handles that garbage in a safe manner. What more could you ask from a dynamic language?