Kyle’s book series, You Don’t Know JS, are available on GitHub, open source and free, as well as being published by O’Reilly.
WTFs are not just things that are funny (like
typeof NaN) or bugs, or ugly code idioms. We have the opportunity to improve those things, and we’ve done a lot of improvement in ES6. Cross-browser quirks are also out — I’m talking about things that are intentionally codified into the spec that produce inconsistent or unreasonable code.
“Many of the things I’m going to share today probably have some line of reasoning that led to them, other than just sheer stupidity.”
The MIN_VALUE Example
It’s pretty clear that Number’s
MAX_VALUE attribute is larger than zero. You might assume that
MIN_VALUE is the smallest number you can get; in fact, it’s the smallest *positive* number you can get. When paired with
MIN_VALUE leads to misunderstanding.
The .toFixed() Example
Kyle hates seeming inconsistency with the period interacting with numbers:
What’s odd to Kyle is that a little bit of a misplaced space can totally mess up the intent of the programmer. This happens especially in blog posts when people aren’t paying as much attention to white space.
“I’ve got a whole lot more crazy for you.”
Coercion is often said to be evil; Kyle thinks coercion is awesome, and the third book in the YDKJS series is about how useful it is and how you should spend time using it. Let’s talk about some coercion implementations that are not WTFs.
This looks nuts; how can something be equal to the negation of itself? We have to understand that the equals and the negation don’t happen at the same time. When you negate an array, you’re taking it from a truthy-value to false, so you’re comparing an empty array to a false.
In the spec, when anything gets compared to an object, both things end up becoming numbers. What number should the empty array become? It becomes 0, and false also becomes 0, and the equality returns true.
If you pay attention to the coercion algorithm, it’s actually pretty reasoned like that, and not as magical as you’ve been led to believe. There are a lot of things that seem crazy and unexplainable, but are actually quite straightforward if you read the spec.
“Coercion […] is not as magical as you’ve been led to believe.”
Coercion Craziness: Numbers
There is some coercion stuff that doesn’t make sense:
Why doesn’t the “.” evaluate to zero? Kyle thinks it may make sense to do this, but especially
Number(undefined), which evaluates to
Number(null), which evaluates to
0, should really match.
In the same vein,
Why does an object turning into a number result in
NaN, while an empty array turn into
0? If you look in the spec, there are some reasons for this; empty arrays turn into an empty string, which evaluates to
“[T]here is some reasoning to it, but it results in inconsistency that drives obsessive-compulsive people like me nuts.”
Objects to Strings
If you try to coerce
o1, you get some garbage — if you try to coerce
o2, you get an error! Why do we have the inconsistency where sometimes we get errors and sometimes we don’t? (Here, because
o2 was created as a
null prototyped object, it doesn’t have access to its
valueof.) Shouldn’t there be an exception to treat this more consistently?
New in ES6: Symbol
Without delving deep into everything about Symbol, Kyle wonders why Symbols can be explicitly coerced and not implicitly coerced:
There are long discussion lists about why TC39 thinks this is the right decision, but this inconsistency is going to trip people up.
“There’s lots of things we can avoid if we’re smart enough, but that doesn’t mean we should create footguns in the design of the language.”
Hating on Finally
finally after a
try/catch condition guarantees that the finally clause will run, even in the case of an error. Here’s some craziness:
There are definitely reasons to use a finally, but if you put an explicit return in the finally, then that return will override the original return!
ES6 Temporal Dead Zone
A variable can be in a special state where it has been declared, but not initialized. For example, the
typeof operator used to be considered pretty safe — you can use it with a variable that didn’t exist. However, if you use
typeof with the
let declaration, it’s not safe:
This is another inconsistency; if
typeof works one way with one type of variable, it should work with another type of variable.