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] < 0) { code }
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?