In 2015, I was consulting for a distance learning program, administered by a major California University, that wanted to replace their current textbook (one of those “Head First” O’Reilly books) with something that had a bit more meat but was very approachable. I immediately recommended this and it was fawned over by both the advisors and instructors. It was also the cheapest option they had in the running (even excluding the fact it can be read for free) as it was competing against traditional text books. One year later, students were polled on it and it was met with a lot of positivity as well.
I got the same feeling and it's very off-putting. KS seems like a dick. It's ironic that so much of his dickishness seems to be reacting against what he takes as Doug Crockford's dickishness. Ah the irony.
I've gotten rid of lots of old programming books over the years, but I've held on to my first edition copy of Eloquent Javascript. Lots of thanks to Marijn for writing this!
I haven't read eloquent JS though, you say it's a different level of learner. Can you expand a bit? Is Eloquent for after "you don't know js" or vice-versa?
Edit: nevermind, reading the TOC of eloquent JS gave me a good enough idea
I know this is off topic but do you, or anyone passing, have a system or tips for how y'all do this? I've got so many programming books but they only collect dust after I read through them without benefit.
https://github.com/getify/You-Dont-Know-JS?tab=readme-ov-fil...
If the second edition is not available, you can read the first edition, just be aware some small things may be slightly out of date.
I'm also glad to see the asynchronous programming chapter significantly reworked - it was materially weaker than the rest of the book because of some weird analogies involving crows and their nests that didn't seem to make any sort of sense to me.
The third edition also gave me the impression that it was a reasonable book to learn JS and the DOM (and a sprinkle of Node.js, for good measure), but that it was a book aimed primarily at experienced people who were transitioning to JS and the web - not beginners (despite the book's efforts at claiming suitability for beginner programmers).
I am glad I am not the only one. I believe he over-abstracted it to it's own detriment.
I went to purchase a paperback earlier this week. Now I will wait for this one to hit print.
It's quite complete and detailed. But as if it wasn't enough the author wrote a second (smaller book) named “Deep JavaScript: Theory and techniques”[2].
Both are free to read online!
I was trying to find what's new in the 4th edition, and following links from the author's website https://marijnhaverbeke.nl/ found this on Mastodon (https://mastodon.social/@marijn/112020092273623390):
> The FOURTH EDITION of Eloquent JavaScript is now online, adjusted to the realities of 2024 and generally touched up.
When I was just starting out I read this book and noticed a small mistake, I was really proud that one of my first contributions to any open source project was a PR to this repo.
I don't work in JS at all professionally but this book has intrigued me for a while at this point after seeing it recommended so often. I think I'll pick up a copy once the paperback is released.
The tricky thing is that "boxes" are the right abstraction for primitive values. After that you need to explain how references work, and that's pretty much the same 'tentacle' concept. This method spares the reader one step, but might cause confusion once they face problems that require that understanding.
And I dispute the claim that "boxes" are the right abstraction for anything in JS. (Boxes may work for primitive values, but nothing further.) Directly seeing names as bindings ("tentacles") not only skips the incorrect "boxes" step, but also causes no confusion or problems whatsoever at any point. (If you have an example, I'd be curious to see it.) (There are some differences in the language between primitive values and Object, but none of them are particularly helped treating variables as boxes AFAICT.)
It's a higher level concept than the variable - a mutable binding is what people usually refer to as a variable, and an immutable binding is the correct term for what people refer to an "immutable variable" (an oxymoron, if you think about it).
2) the ‘binding/tentacle’ metaphor works just fine for primitives and the ‘boxes’ model adds more complexity.
I'm typing on phone so for a quick example:
let a = [];
let b = a;
a.push(1);
and consider the value of b now (or the fact that we could write "const" above because the binding is constant, even though we mutate the value). Or see the equivalent for Python by Ned Batchelder, which has more examples and elaboration: https://nedbatchelder.com/text/names1.html[1] https://www.amazon.com/JavaScript-Definitive-Most-Used-Progr...
This was an interesting line of thought to digest. He's right, of course. Programming is probably still in it's infancy.
Studying and learning about programming however, can make you believe it's some ancient art mastered by the giants of our recent past, the perfection of which is never to be surpassed again.
(even though you do need a namespace when creating svg elements through createElementNS, both "of course" and "unfortunately", and of course you need namespaces if you're creating an actual stand-alone SVG document)
I really like the Deno approach so far. I prefer TS mostly these days as well as the esm stroke modules. I think node just made usage harder in their approach. I understand why, I still disagree on the solution.
This is from the chapter on HTML and JS (emphasis mine). It is funny to see how govt agencies and criminal organisations are mentioned in the same breath. How did we end up here?
another good one for my learning was "secrets of the javascript ninja"
How does this one compare as an all-in-one? Being up to date is a win, but I'm wondering about the quality of the writing.
A distinction should be made between errors and exceptions. In JavaScript and many languages, we conflate the two and use exception handling as logic flow control. In my experience, this can end up being a headache and encourage unnecessarily weird structuring of code.
Look at this example from the page on errors:
---
function getAccount() {
let accountName = prompt("Enter an account name");
if (!Object.hasOwn(accounts, accountName)) {
throw new Error(`No such account: ${accountName}`);
}
return accountName;
}---
The possibility that a user will enter a account name that doesn't exist is not an exception, but we are treating it like one in this case. In order to handle this exception when getAccount is called, we have to wrap it or some higher level scope in a try-block and then regex-match the error message if we want to handle it differently from other errors.
You might be saying "it's just an example", but there's plenty of production code in the wild that is written this way. Maybe this could be improved by subclassing Error, but now you're having to manage a bunch of clutter and using object-oriented features as a way to reliably determine what kind of exception you're dealing with.
I find this pattern to be preferable:
---
const ACCOUNT_NOT_FOUND_ERROR_CODE = 1;
function getAccount() {
let accountName = prompt("Enter an account name");
if (!Object.hasOwn(accounts, accountName)) {
return {
accountName: null,
error: {
code: ACCOUNT_NOT_FOUND_ERROR_CODE,
message: `No such account: ${accountName}`,
}
};
}
return { accountName, error: null };
}---
Then we can call the function like this:
---
const { accountName, error } = getAccount();
if (error) {
if (error.code === ACCOUNT_NOT_FOUND_ERROR_CODE) {
errorModalService.show(error.message);
}
} else { // do something with the account name
}---
No doubt, you may still want to catch exceptions at a higher level scope, but at the nice thing here is that exceptions (almost) always represent actual unexpected conditions that aren't being handled properly while return values with error codes represent expected conditions and can be handled like any other logic in your code. It also reduces any ambiguity of how an error should be handled but without subclassing. An error can even contain more information than just a message if you want it to.
Also, if you really want to ignore an error for some reason, then you can just pretend that the error doesn't exist. No need to use a try-catch where the catch-block is a no-op.
I wish we'd encourage this sort of pattern, but maybe that's one of many pipe dreams of mine.
It is true that exceptions "bubble", and plenty of developers take advantage of that behavior. In my opinion, it is not helpful for errors that are expected to happen as part of normal application behavior. Bubbling of errors creates a sense of logical indirection. Errors as return values communicate that likely nothing " wrong" actually happened. Good communication through code reduces the amount of time developers spend using the wrong assumptions when debugging.
There is also no reason why errors in a return value can't be returned by the caller. When you learn to love objects/hashes as return values, you can get the same benefits of bubbling but with a more clear path to follow when getting a picture of where a value is coming from and why.
In the case of actual exceptions, like accessing a property on undefined, an error being thrown is appropriate because, like you say, it can be bubbled up. The nice thing about reserving exceptions for this sort of thing is you might get away with a single try-catch at the highest scope and have a single straight forward error modal for when an unexpected problem occurs. Then you can otherwise implement errors in your code without the possibility that they will escape through bubbling and trigger behavior that is not immediately obvious when following the path of execution.
This is not to say that the tradition of using errors and try-catch for normal application control flow is inherently bad. Its just another tool. I do subjectively believe they are counter productive when used that way, and encourage others to try something like my approach. I think we would benefit by making it a standard practice.
I learned JS from the second edition.
Incredible resource.
CH 5 : "Higher Order Functions" seems a nice segway into one of my favorite, lesser known js util libraries Ramda.js
Nothing changes in last few years. We still go in with what we incorrectly assumed at the start.
According to the author, Marijn Haverbeke.
Given so many are just on Github and very well known/linked-to I doubt they even put any special effort into getting these specific resources.
The 'Eloquent JavaScript 4th edition (2024)' in Dark Mode
Also how this person is so productive? I really would love to read on how he manages his time and priorities.
>2**57
144115188075855870
>2n**57n
144115188075855872nhttps://github.com/python/cpython/blob/d864b0094f9875c5613cb...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
I've been having to do some hacky things to represent numbers on an astronomical scale for my star system/planet generators.
From a quick browse:
- # for private properties
- ESM imports in node
- hasOwnProperty -> hasOwn (TIL: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...)
- Math.pow -> **
- coverage of `function*` generators (https://eloquentjavascript.net/11_async.html#h-o+cFzGGhnz)
https://github.com/marijnh/Eloquent-JavaScript/compare/3rd_e...
It was challenging and made me question whether or not I had it in me to code. Turns out, I could, and, vis-a-vis my peers, exceptionally well.
Well, I took me, but this book was my first real introduction to computer science.
Funnily enough, I didn't then and don't now personally care for the author (he seems untalented as a teacher), but I feel he accidentally made a good resource in his hubris.
(Like expecting that just because you declared something as type X, that it guarantees at runtime it will always be type X, but it won't. You may get data from an API that _says_ it returns type X but the contents don't match. That can be valid code that compiles and has weird runtime behavior)
This is exactly why I never recommend TypeScript to new developers.
A similar problem (that used to be worse) with people learning JavaScript is the lack of separation between JavaScript and the DOM + browser APIs. 10+ years ago, people have told me how much they hated JavaScript and when probed about it further, would admit that it’s actually the DOM or new/inconsistent browser APIs that have caused issued.
JS has a number of its own flaws and quirks, yes, but there are two fundamental issues that make it harder to approach as a new learner (as opposed to, to say, Python) are how tightly coupled it has historically been to it’s primarily application case and how high or low level is this language?
The idea that someone is good at another language so they'll automatically be good at another is a common misconception. In fact, they're likely to be worse because they're less likely to spend time trying to learn things from the ground up and less likely to write idiomatic code.
It's especially bad with js/ts because of it's popularity (so lots of new programmers that complain about how NaN doesn't equal itself), and because it's the defacto web language so lots of people are forced to use it as a secondary language that don't want to spend time learning it.
Why is that? If you want them to learn JS, teach/recommend them to learn JS?
Compile-to-JavaScript languages come and go, but JavaScript has remained. First learning vanilla JavaScript makes sense, and then add TS on top if you really have to. At the very least they'll be prepared for when TypeScript goes out of favor.
This is both a curse and the secret behind its success - it's arguably not a separate language, but instead an annotation layer on top of the existing language for encoding and checking your static reasoning and assumptions.
The chances of it going out of favour are very slim, there's a giant ecosystem built on it and the language is very well loved by devs (should be second only to Rust).
Microsoft has 50 people on payroll working only on TS. Any competitor needs a gargantuan investment.
An anecdote: I was sold a similar story on CoffeeScript back in the day, stressed myself out learning it, only to discard it a couple years later. TS won't have an identical fate as its shepherded by Microsoft, but eventually it will go the way of the dodo (whereas core JS will still be humming along).
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...
JavaScript doesn't have integers. Everything is a float. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Although it has BigInt now.