YDJKS — Up & Going: Lessons Learned

My personal learnings from You Don’t Know JS: Up & Going

Anton Paras
9 min readOct 11, 2018

Popular yet Misunderstood

JavaScript is quite an interesting language. It’s mechanics are interesting, for sure. However, I specifically mean that the community surrounding JavaScript is interesting.

Not to bury the lede, my point is that JavaScript is arguably the most popular programming language in existence right now, yet it is probably one of the most misunderstood languages as well. According to GitHub’s Octoverse 2017 results, JavaScript is by far the most popular language. 2.3 million GitHub repos contain JavaScript. That’s more than the 2nd & 3rd most popular languages’ repo-counts combined (Python: 1 million, Java: 986K).

Source: https://octoverse.github.com/

JS’s popularity is indisputable. However, for such a popular language, how much do people really understand it? How much do people understand its internals workings, its mechanisms — its guts?

Prima facie, you’d think that popularity begets widespread understanding. However, this isn’t the case for JavaScript.

In social circles both online and in-person, you’ll find hordes of people disparaging JavaScript for features like type coercion, prototypal inheritance, a single-threaded engine, closures, etc. These are core features near JS’s heart. For many people, features like this are foreign to their native language (e.g. Java). Instead of learning about these features properly and then fairly evaluating them, many people have impulsively dismissed them altogether as being oddities, useless idiosyncrasies, quirks, or worse, even bad parts. Such is the raison d’etre for Douglas Crawford’s 2008 book, JavaScript: The Good Parts.

This has been the fate for JavaScript for years. If it weren’t for its incumbency as the web programming language, JavaScript would certainly be a dead language. However, its home in our web browsers has safely secured its existence and continued life. Yet, because it’s been spurned so heavily, many web developers have only a shallow understanding of the language — only enough to tweak jQuery plugins they copy+pasted, or enough to use a framework that will abstract JS’s true nature away.

Popular yet misunderstood, that’s JavaScript.

It’s such a shame too, for a deeper understanding of JS will certainly pay dividends in a web developer’s career. Vanilla JS will be around for a long, long time (maybe eventually ClojureScript/ReasonML will be supported natively in the browser too?) whereas your favorite libraries and framework today may fall into disuse in the near future. AngularJS developers may have been all the demand back in 2013, but that’s hardly the case now. The same will be true for React and Vue developers as well. JS developers can trust in their job security for a long time to come.

Furthermore, if you’re using a JS library/framework, oftentimes you’ll have bugs that aren’t caused by the library/framework, but by a fatal misunderstanding of either (1) how to write your application’s business logic using vanilla JS (2) how your framework is using JS.

A deeper understanding of JS can really go a long way.

It’s for this reason that I’ve decided to start reading Kyle Simpson’s legendary book series, You Don’t Know JS (kudos to Kyle for choosing such an apt, yet hilarious name). This series is revered among the JS community as a thorough yet approachable guide to JavaScript’s insides. It consists of 6 books: Up & Going, Scopes & Closures, this & Object Prototypes, Async & Performance, and ES6 & Beyond. Quite the collection. I should note that this series is available for free on GitHub. With more than 89,000 stars, this series has developed an almost-authoritarian reputation on JavaScript education.

Source: https://github.com/getify/You-Dont-Know-JS

For each of the 6 books, I’ll write a blog post sharing my personal learnings, thoughts on JS’s “quirks” and how they can be appropriated for better use, idiomatic ways of accomplishing tasks in JS, and more.

In this post, I’m starting with Up & Going, which mostly aims to teach complete beginners about the basics of programming and to briefly cover topics that will be expanded upon later in the series.

I’m not exactly a beginner to programming, and I would say I have an intermediate understanding of JS. So, I could have skipped Up & Going altogether, but for the purpose of completeness, I didn’t. Furthermore, there’s no shame in going back to basics, and I actually learned a few things here and there! (mostly putting names to things, like learning that == is called “loose-equals. But I also learned some more substantive things as well.)

However, because of Up & Going’s rudimentary nature, I don’t have as much to discuss as I’m sure I’ll have for the subsequent books. So, the learnings on this post will be a bit sparse. I’m sure upcoming posts will have much more to offer for intermediate-level JS developers.

Anyway, enough chit-chat, let’s dive in!

Return Value of an Assignment Expression

An assignment expression returns the right-hand side’s value. So, if you do something like

a = 2

that expression does two things:

  1. assigns 2 to a (assuming strict mode is disabled or a has already been declared)
  2. returns 2.

This example will probably clarify what I mean:

I actually didn’t know this before reading about it in Chapter 1 of Up & Going. However, in the past, I have seen some tricks that alluded to this behavior.

In particular, I saw a JS-quirks question that asked what the following statement did:

const a = b = c = 20;

In the past, when I ran this code, I saw that a, b, and c were all assigned 20, but I wasn’t completely sure how it worked. Now, I know why!

I know that, if you do c = 20, and c hasn’t been declared yet, then the JS engine will implicitly declare c on the global scope. (if strict mode is enabled, a ReferenceError will be thrown instead.)

Now, with that knowledge, I can fully explain what’s happening in

const a = b = c = 20;
  1. Assignment Expression c = 20: c is declared on the global scope and assigned 20.
  2. Because c = 20 is an assignment expression, it returns the value of the right-hand side, which is 20. This leads to…
  3. Assignment Expression b = 20: b is declared on the global scope and assigned 20, which came from the evaluation of the prior c = 20.
  4. Because b = 20 is an assignment expression, it returns the value of the right-hand side, which is also 20. This leads to…
  5. Const Declaration const a = 20: a is declared as a const and assigned 20, which came from the evaluation of the prior b = 20.

Following this logic, I hypothesize that, if I enable strict mode before executing

const a = b = c = 20;

then a ReferenceError should be thrown to prevent c from being implicitly declared on the global scope.

Exactly right!

Operator Names

Because Up & Going is an introductory book, it covers introductory topics. For the most part, I already knew the material covered, but what I didn’t know were the names for certain things, especially operators. It’s always nice to put names to things you’ve always known, and I did that for a few JS operators.

. and [] are accurately called property accessors.

== and != are accurately called loose-equals and loose not-equals respectively. (Note that I did not say inequality, because that terminology is reserved for the comparison operators <, >, etc.)

=== and !== are accurately called strict-equals and strict not-equals respectively.

>= and <= are accurately called greater-than or loose-equals and less-than or loose-equals respectively.

Explicit Coercion

I knew that you could convert non-number-typed values to numbers using Number(), but I didn’t know that you could convert non-string-typed values to strings using String().

But to be honest, I think I’d rather just do the old trick of adding a string to a number, to convert it to a string.

Most of the time, you’re adding a number to a variable that already has a string in it anyway, so in reality, string interpolation with numbers is more like

someVarContainingAString + myNum

which I think is better than

someVarContainingAString + String(myNum)

== vs ===

Prior to reading Up & Going, I thought that the delineation between == and === was that

  • == checked for semantic equality
  • === checked for semantic equality + type equality

Well, Kyle was very quick to correct my misunderstanding.

As it turns out, both == and === check for value equality, but

  • == allows type coercion
  • === prohibits type coercion

So, if you do a == b, and a and b aren’t immediately equal (for example, "3" == 3), then JS will perform a series of type coercions on either a or b (or both) to see if they’re equal in other type-representations. If so, a == b will evaluate to true, otherwise false.

However, if you do a === b, and a and b aren’t immediately equal, then JS will immediately return false. No type coercion will occur. For this reason, === is called strict equals.

I’m happy to have cleared up this misconception, thanks Kyle!

Standalone Blocks

I already knew this, but I still feel like it’s worth sharing.

You can have standalone blocks in JS. For example,

This is potentially useful for restricting the scope of your variables/bindings. Like, if you wanted to keep a variable within a very small scope, you could do that using let / const and a standalone block.

In pre-ES6 JS, only var was available. var produces variables that are function-scoped. let / const are block-scoped. So to achieve this effect with var, you’d have to use a var in an Immediately Invoked Function Expression (IIFE). You couldn’t just use an empty block.

JavaScript’s Data Types

As of today, JS has 7 data types:

  1. Boolean
  2. Null
  3. Undefined
  4. Number
  5. String
  6. Symbol (New to ES6, is essentially like a universally unique string.)
  7. Object

This might be surprising, because it implies that things like arrays and functions are Objects. Indeed, this is the case! You can treat functions and arrays just like objects: you can assign key-value properties on them:

Note: it’s almost certainly bad practice to use arrays and functions like objects. This was just for demonstration purposes.

Comparison Operators & Implicit Coercion

Implicit type coercion also occurs for the comparison operators: <, >, but in a different manner from the equality operators.

Consider a < b.

If a and b are both strings, then the two values are compared lexicographically (aka alphabetically).

“abc” > “aac” because “abc” would occur later, alphabetically speaking

However, if either a or b (or both) is not a string, then both values are coerced to numbers. From there, comparison happens as it typically would with numbers.

The pitfall is when either value cannot be coerced into a number. If a value cannot be coerced into a valid number, it defaults to NaN (Not a Number). NaN exhibits unusual behavior during comparisons.

NaN is neither greater than or equal to any number.

So that’s why this happens (Objects cannot be coerced into numbers):

Additionally, 42 == {} is also false. Recall that, for loose-equals, a series of type coercions occur to a and b to check if their values are ever equal. I didn’t say in which order/manner the coercions occur, mostly because Kyle didn’t explain it in the readings.

However, he did mention that something like 42 == {} would be eventually be coerced to 42 == NaN, which expectedly yields false.

Thus, you can end up with a seemingly contradictory snippet of code like so:

That’s all for now. Stay tuned for the next post on Scopes & Closures!

--

--