Hacker News new | past | comments | ask | show | jobs | submit login
Deep JavaScript (exploringjs.com)
337 points by noch 11 days ago | hide | past | favorite | 62 comments

JS has been my main language for the last decade and Axel (the author of the book) is my go to source when it comes to understanding upcoming features. I frequent proposal repositories, read the standard, and still find myself learning something new when I read an article from Axel on the subject. I have not read the book, but I'm sure it's written with the same rigor and clarity as all Axel's writings.

+1 as a non-JS programmer.

His "Exloring ES6" saved me when I was lost as knowing only about good old ES5 (or maybe ES3? I don't even remember.)

"JavaScript for impatient programmers" [2] also looks promising. Just purchased one. The PDF looks great although the cover is meh :-)

[1] https://exploringjs.com/es6.html [2] https://exploringjs.com/impatient-js/

This book is very well written, and interesting (at least to me). I didn’t know that JS didn’t have exceptions at first.

Clicked through to https://exploringjs.com/deep-js/ch_type-coercion.html and I have to say that's already a bit questionable. The idea is there, but the writing around it is shaky (if you want to explain coercion, showing JS code without coercion without explaining that's what you're doing is not the best way to explain things to folks looking for answers).

Same for https://exploringjs.com/deep-js/ch_copying-objects-and-array..., the idea is there, but the text isn't great (is it only for objects and arrays? if I'm new to JS but someone taught me about Set and Map, can I assume those always deep copy?).

It's a great start, but it can definitely do with a few QA (rather than editorial) passes.

[I’m the author of “Deep JavaScript”.]

Don’t forget that this book is for people who already know JavaScript well. It doesn’t try to explain the basics. This book does, though: https://exploringjs.com/impatient-js/

Sure, but as an expert, explanations that holds up for everyone are always preferred no matter what level of book I'm reading, compared to an explanation that makes sense "if you already how it works". In both cases linked, the text feels incomplete or even just "wrong, were it not for the fact that I know what you actually meant".

This is a bit off-topic

But I never understood prototypes and prototype inheritance, and how does that "map" to "classic" inheritance, from Java or C++. And I worked in FE for about 10 years...

It seems you can model "classic" inheritance using prototypes, but... there is something more there that I don't understand. I started using ES6 "class" as quickly as I could, but I still wish I understood what .prototype and .__proto__ is and how to use it. I feel like I "miss" a lot of JS when misunderstanding prototypes.

But none of my colleagues know either, so I guess I at least know what I don't know.

Around 30 years ago (five years before advent of Javascript), I built a successful company around a distributed network programming framework that used prototype based objects. Objects in object oriented systems usually share some behavior via common methods, and they share some structure for their data members; the methods and structure are described by the object's class. Classes are language constructs with their own complex behaviors.

A class is like a blueprint used by the language compiler and runtime to build (allocate) objects. In languages like Python, Ruby, Smalltalk, or Common Lisp these classes are present in some form at runtime controlling the memory allocation of objects, the initialization of member fields, the dispatching of generic or virtual functions and so forth. Since the classes are present in some shadowy form at runtime, they themselves have behaviors controlled by meta-classes which in some languages can be manipulated at runtime (e.g. monkey-patching).

Prototype based object systems don't use classes to accomplish this sharing of behavior and structure. Such systems have a conceptually simpler set of primitives to accomplish the sharing and classes aren't needed. In prototype based systems one can clone an existing object, even an empty object. After cloning an object one can add fields to the object.

Structural sharing is easy with prototypes. If a program would like to make use of objects representing screen coordinates, first construct a prototype:

    Coordinate2D = clone(empty_object)
Like fields, methods can be added to the prototype:

    Coordinate2D.clear = {self.x = 0; self.y = 0}
Next to create an object of type coordinate just clone the prototype:

    location = clone(Coordinate2D)
    location.x = 10
    location.y = 16
Prototype based systems are appealing because of the underlying language semantics and runtime implementation are very simple.

Smalltalk, CLU, Common Lisp's CLOS (The Art of the Meta-Object Protocol), and Self all inspired design decisions that went into the Tivoli Systems distributed programming framework.

I don't think that's how prototypes work in JavaScript though. The newly created objects refer to a chain of prototype references, and changes to the underlying prototypes will affect already existing objects.

My example was a simple one, and you are right, Javascript objects contain a reference to their prototype object from which they are cloned and via which they can inherit behavior. However, this is handled a bit differently in Self and in the original Tivoli Systems actors. The details between these systems are different so my example left out many interesting details.

In JavaScript, classes are mostly just a slightly weird way of setting up prototype chains.

Diagrams help me understand how this works. At the following link, you can see the source code of a simple class and a diagram (section 29.2.2) that shows how all involved objects are connected: https://exploringjs.com/impatient-js/ch_proto-chains-classes...

> how does that "map" to "classic" inheritance, from Java or C++

I'd recommend doing it in two steps.

First, you need to get from the Java/C++ perspective of "classes are compile-time templates" to a perspective of "everything is an object". Python is a good example of the latter, as is Smalltalk (the latter is more 'extreme', but also less widely used):

    $ python3
    Python 3.8.9 (default, May 27 2021, 03:09:34) 
    [Clang 7.1.0 (tags/RELEASE_710/final)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class A:
    ...   pass
    >>> myA = A()
    >>> myA
    <__main__.A object at 0x10670c490>
    >>> A
    <class '__main__.A'>
    >>> myA.__class__
    <class '__main__.A'>
    >>> class B(A):
    ...   x = 123
    >>> myA.__class__ = B
    >>> myA.x
Once you're comfortable with that, you can take the second step: from a Python/Smalltalk perspective of "everything is an object; when a slot isn't found in the instance, we fall back to looking in its class", to reach the Javascript/Self perspective of "everything is an object; when a slot isn't found in an object, it can tell us to look in another object". That 'other object' is the prototype.

All we're doing in the second step is removing a distinction: Python/Smalltalk have a built-in notion of "class", where some objects are classes and others aren't. Javascript/Self just have objects: we can use any object as a prototype for any other.

There is a big difference between Java and C++ classes. In C++ classes are not present at runtime, but in Java they are present at runtime, are accessible via reflection API and can be loaded dynamically at runtime.

A class is a blueprint you go to for constructing new objects. A prototype is an object you create once that is copied to a variable when the constructor is called. That is how I understand it, but maybe someone else can explain further.

You can think of a prototype as a fallback for your object.

If something doesn't exist on your object, JS will check if it has a prototype and look there transparently.

Now, if you got a prototype chain, JS will move through it in the hope to find what you wanted to access on the original object.

try to access obj.a

not there?

try to access obj.prototype.a

not there?

try to access obj.prototype.prototype.a


The nice thing is "this" will usually (if you call a function as method and not pass a reference of it around for callbacks and such) refer to the object and not the prototype. Also, writes happen on the object.

I think Kyle Simpson's You Don't Know JS does a good job about this. But on the other hand, it seems like it's usually safer to keep it simple, treating it more or less as classical and using classes, to make a codebase that others can relate to well.

This looks like a good book but boy, is JavaScript convoluted. Not bashing it. Just read the chapters about shallow and deep copies.


Fortunately, it seems to be convoluted as a result of its underlying simplicity, perhaps?

The reason the article you linked is so long (instead of just being the standard OOP shallow- vs deep-copy disclaimer) seems to be because JS objects and classes are just dictionaries (in the Python sense of the word) with certain magic fields to control dispatch, inheritance, etc. The docs need to take care to explain how certain operations interact with those magic fields. So, still convoluted, but IMO better than if it were convoluted because everything was a built-in special case under the hood.

At least that's my impression as someone who doesn't write a lot of JS. Happy to be corrected.

That's also my impression as someone who used to write a lot of JS - everything is either a value, dict or array, and once you learn some guardrails on how you write JS code (in your words, 'explain how certain operations interact with those magic fields'), it becomes remarkably nice to use.

Isn't shallow vs deep copying a thing in most languages?

It is. JavaScript seems to have quite a few ways of getting it wrong though.

Do you have any empirical evidence it is more convoluted than equivalent popular languages?

I wasn't saying it is more convoluted than other languages. I just found it interesting that there are so many idiosyncrasies and gotchas.

It is appreciable that he offers a discount for those for whom USD is ridiculously expensive in their own currency or have previously bought his books. Though I wish he would rather send the discount code via email rather than ask for a mobile number, which is rather invasive.

Probably he wants the phone number because it indicates which country someone is from. I mean sure you can still get a temporary number from another country online, so it’s not 100% accurate. Or you could have recently moved countries and still be using the phone number that you got in your old country. But many people will probably use their actual number and of those people most probably have a number from the country they are living in.

This is very useful right now because I'm about to embark on learning js to be able to write aws-cdk infrastructure code, after finding Terraform to be annoying in some ways. (mostly its declarative nature means any logic can be difficult to shoehorn in). Decided to buy the javascript for impatient persons book and start reading it on my tablet.

(more offtopic, but we'll be using TypeScript, so I'm going to need to find some good guides for that too - any suggestions?)

I you are just learning the language, I'd suggest skipping this particular book altogether for now.

I'd start with a "Re-introduction" tutorial on MDN [1] followed by another Axel's book - "JavaScript for impatient programmers" [2]. Don't read the whole book at first, focus on specific chapters: parts on Modularity, Collections and Asynchronicity.

As for TypeScript, the official Handbook [3] is great. Don't dwell much on intricacies of TS type system. Use it here and there to aid your editor or IDE in highlighting mistakes in your code, and get deeper into it once you get a good grip with JavaScript in general.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re... [2] https://exploringjs.com/impatient-js/toc.html [3] https://www.typescriptlang.org/docs/handbook/intro.html

Excellent, thank you! I bought the impatient book, and I'll check out the TypeScript handbook too.

It's going to be a shock going from declarative DSLs like Puppet and Terraform to a real coding language! Most of my coding experience has been in shell scripting and some Perl/Ruby from ages ago.

IMO you should try to keep the code as DSL as possible, and only use the imperative features when it makes a lot of sense. For instance if you have like 10 security groups to add and you just put it in a for loop. You should not embed actual account numbers, regions, etc etc in your code (i.e. a cdk synth should not show arns with arn:aws:1283830383 but rather arn:aws:ACCOUNT_NUMBER) you do that by doing something like:

resources: [`arn:aws:${cdk.Aws.AccountNubmer}`]

(I know I got the arn format wrong and probably messed up the account number, but you get the gist I hope)

The reason is if you follow those rules strictly enough, you can still deploy that template in most accounts (dev, test, prod and so on), which has always been one of the core strengths of CF (and others) when done properly.

And I prefer to NOT use If statements in typescript if it can be done in Cloudformation with conditions or other items. For instance, if you only want to deploy a secondary rds slave in prod, use a CF condition and not a typescript 'if (accountNumber === myProdAccount)' because that means your typescript needs to know which account it's synthing for, which by default it does not.

IOW, try to use typescript to build DSL that's still in the spirit of DSL and you'll avoid a lot of traps that novices get themselves into.

I used the CDK for quite some time now and I can say that it's usually simpler to write things in TS than YAML.

Being able to throw in some loops here and there is quite a simplification on its own.

Assuming you're already familiar with other programming languages, I'd strongly recommend O'Reilly's JavaScript The Definitive Guide. The 7th edition came out not long ago, and it is by far the best version. They've pared down the section on the JS in browser to focus on all of the new JS functionality and a bit on server side with node. It covers async, generators, and modules in detail. It includes detailed sections on JS's annoying type conversion behavior. It doesn't have anything on TypeScript however, oddly choosing to talk about Flow instead.

I'm pretty comfortable with JS and Typescript so I might be at an advantage that I don't perceive but CDK stuff doesn't require a good grasp of either language. If you are familiar with at least one other typed language you'll be fine. You'll spend more time digging through the Github issue tracker trying to figure which parts of AWS functionality are supported in the CDK and the assumptions the whole thing is built on.

This is true. Have guys new to JS/TS doing stuff in cdk quite a bit. Fortunately there's not much complexity to CDK's framework and if you stick to L1 constructs it's very very close to just writing the YAML (Minus minor casing conventions and other relatively trivial things)

You can check out my book (it’s free to read online): https://exploringjs.com/tackling-ts/

I bought it, thank you for taking the time to write such a good book!

Thanks! I’m glad to hear that.

I have been using and advocating Javascript for over 10 years.

I believe language evolution like ES6 are more than welcome. However, I have the impression that the path taken by the committee and the new proposals do not bring great gains (whether in UX, code reading, performance, etc.) but bringing unnecessary complexity.

On the other hand, other serious problems such as the mathematical and numerical part of the language are being left aside.

From what I’ve read, TC39 acknowledges that this is important and is working on fixing JavaScript’s deficiencies in this area:

– BigInts (arbitrary precision integers) were a recent addition: https://exploringjs.com/impatient-js/ch_bigints.html

– A proposal for `Decimal` (base 10 floating point numbers with arbitrary precision) is currently at stage 1: https://github.com/tc39/proposal-decimal

Can you describe more about what are the serious problems in the math/numerical parts? (curious, not skeptical)

I’d characterize JS as having moderately annoying numeric limitations rather than serious problems. Two that come mind:

Not having 64 bit integers is a large annoyance. There’s workarounds but none of them are especially ergonomic.

The expression n | 0 is a signed 32 bit int. The expression n >>> 0 is an unsigned 32 bit int.

The URL should go the the front page of the book (https://exploringjs.com/deep-js/) rather than the table of contents.

This looks really good and I'll probably read a little here and there when I get the urge. But I don't think deep knowledge of JavaScript will pay off in today's web development world.

I deep dived JavaScript many years ago so I could move away from C#. It was only useful in interviews so I could answer all the esoteric trivia. On the job it was using JS frameworks and libraries like Lodash. And then TypeScript came along and eclipsed it all together.

You're better off learning just enough JavaScript and then deep diving TypeScript and Angular, React, or another framework.

I’d agree that if you’re looking to have a career in front-end your order should be some JavaScript, then React/Angular and possibly Typescript, but after that I’d still recommend you go back and really learn JavaScript. It doesn’t often happen but sometimes you run into a situation where that knowledge does come in handy. You can introduce bugs in your React code if you don’t understand closures for example, to use a library like redux-saga you need to understand generator functions, you may run into code where you need to know how the “this” keyword works, etc. A more junior dev needing help with those is fine, but I’d expect a senior dev to be able to navigate those type of situations on their own most of the time.

Solving bugs is important but more to your point a good senior dev knowing those things provides flexibility and empowerment. Sometimes there is a more direct solution than what the internally available tools provide.

There's an effect where young people watch Seinfeld and find it unfunny and derivative. That's not because it's true, but because they watched stuff that had copied what Seinfeld did first.

People look at Crockford's "JS: The Good Parts" and comment on how it's obvious. It wasn't obvious then and that's why the book was so well received. Languages have radically copied the good parts JS since then while JS has lost most of the worst parts which means that when you move to JS, it's a much less radical shift.

First-class functions and closures with all their implications (IIFE, module pattern, callback/continuation, lambdas, .map() and it's ilk, currying, etc) have all caught on as a result.

Immutable data or more precisely, treating data as immutable and letting the GC sort it out was a huge boon for UI development.

Promises/futures seem ubiquitous these days, but that's strictly because of JS libraries introducing them in 2005 (twisted library introduced them in Python in 2001, but Python wasn't super popular then and twisted has never been popular at all).

I'd also say that the push for pattern matching has also been fueled by ES6.

In truth, StandardML (SML) and Scheme had been doing most of this (and much more) since the 70s, but for whatever reason, they have been rejected by mainstream developers. Hopefully, one day we will recognize this and switch development away from languages with these features tacked on to ones where they are baked in and cohesive.

what you're saying is the equivalent of you'll learn django orm or whatever orm instead of SQL. Yeah in the short term, you've immediate productivity gains. But in the long term, you lose out as the ORM | Framework API's churn - while the base language itself remains stable.

Invest in the basics, and you'll never lose. SQL, HTML, JS. No need to keep learning or relearning frameworks or libraries.

I'm finding the serif font, whitespacing & line width, and inline code style quite hard to parse.

The whole thing reads (visually) as a bit of an indiscriminate jumble.

The following changes help (me). I'd also look at colouring some other sections to clarify the visual flow of document,


pre { background-color: #EEE; font-size: 1.2em; line-height: 1.4; margin-left: 1em; padding: 1em; }

body { font-family: sans-serif; font-size: 1.2em; }

#page-content { margin: 2em auto 2em auto; max-width: 40em; font-size: 1.1em; line-height: 1.7; }


I had no problem with parsing the type. I thought it was clear.

But I found it odd that there is no copyright information, date of publication, etc.

Whether we've hit Peak JavaScript, or are looking at Long JavaScript, sooner or later we'll face Big JavaScript.

Not sure why author uses the phrase "pattern matching algorithm". There is nothing algorithmical about it. This is just a pattern matching language feature similiar to Haskell's. And since JS is dynmatically typed, I believe this is really just sytnax sugar at the interpreter level.

Unless there is something time/space-specific about it, invoking "algorithm" feels to me an abuse of terminology. Of course will love to be enlightened otherwise.

I've always found Raganwald Braithwaite's JavaScript Allongé to be a wonderful demonstration and application of the kind of idiomatic classless JavaScript you get when you understand the language's OO properties.

I haven't read the book yet, but the topics themselves are quite intriguing and looks useful. Definitely a good hammer to break out of the "advanced beginner" chamber.

Has anybody read this book? I'm curious about the quality. It's one of those things that could either be really great or really misguided.

Yeah, it's good. Working with with learners, I always recommend his books (particularly the ES6 one) as reference once they're past the basics. He's very good and not someone who disseminates much information that isn't just practical explanations of and realistic usecases for spec. Slightly dry, but very concise. This one's [naturally] slightly more in depth, but it's IMO a necessary addendum to previous books/articles -- something that builds on them for slightly advanced usecases. Sibling comment says you'll write better code in 99% of jobs if you don't read it: I don't think that's true at all. Deep copying, for example isn't uncommon.

Referencing the few areas of it where I have domain knowledge I'm impressed. Lots of really good info. If nothing else it's a great starting point for research on various topics.

Axel Rauschmayer has been writing JS books for a while, he's quite knowledgable. I would recommend

Haven't read it but since it from the same author who writes these 'to the point' blogs - https://2ality.com/ I believe the quality would be good.

+1 it looks great.

I glanced through it and it has some interesting stuff, but I suspect you'll write better code in 99% of jobs if you don't read it, and don't know about most of the techniques described

Why do you think this? I'd be interested as to why you came to this conclusion.

I might be missing something; is the book free online..? Or, is there content that's paid only?

> https://exploringjs.com/

"Most of the books are free to read online! You can also buy offline versions."

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact