Check out a free preview of the full Deep JavaScript Foundations, v3 course
The "toNumber" Lesson is part of the full, Deep JavaScript Foundations, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Kyle discusses the behavior of the abstract operation toNumber.
Transcript from the "toNumber" Lesson
[00:00:00]
>> Kyle: So what about ToNumber? This one's a bit more interesting cuz there's a lot more corner cases involved. Anytime we need to do something numeric and we don't have a number, we're gonna invoke the ToNumber abstract operation. So what are some examples of those? Some of them are well formed, but some of them are strange.
[00:00:15]
Empty string, I think, is the one that drives me the most bonkers. Empty string, whenever numericofied, or whatever the right word would be for that, becomes 0. Now as far as I'm concerned, empty string is the way that you say I have no values in a string. It's the absence of any string value within that type.
[00:00:39]
There's no other representation of the absence of values within the string type, other than an empty string, as far as I can tell. So if it's the absence of value, why on Earth does it, when it becomes a number, become an actual number like the number 0 instead of the number that already exist in the language, that represents we don't have a valid number?
[00:00:58]
Which would have been NaN. I'm ranting on this particular point because it turns out, we're gonna see that's the root of all evil in JavaScript. But most of the rest of these are all very sensible. If you had the string 0, it becomes 0. If you had the string -0, here's a surprise, it actually becomes -0, very cool.
[00:01:17]
It strips off any leading white space, trailing whitespace, and leading zeros, so we just get 9. It handles floating points well. Some weirdness with the trailing and leading dots, but those are syntactically valid. It even handles other's bases, like in this case, hexadecimal. So the numerification, I don't know what that word should be, of a string value is fairly sensible, with a couple of weird corner cases.
[00:01:45]
What about dealing with the numerification of falses or trues, or nulls or undefined? What about those other primitives? Well, false becomes 0, true becomes 1. And at the outset, you might think, well, that makes complete sense. Historically, we've always thought of false as being 0 and true as being 1, from bit-wise perspective.
[00:02:09]
I'm gonna go, I'm gonna put my foot down and say that was a terrible idea, that false and true, when represented as numbers should have represented as NaN. And you'll see why a little bit later. But that, I don't like that decision. But I understand why, within the context of greater programming, that's probably what most people would expect.
[00:02:29]
Null becomes 0, okay? But undefined becomes NaN, what? Here they decided to finally use NaN, but they didn't use it with null? Somebody explain that one to me. Null should have been NaN, just like undefined should have been NaN. Okay, so when we use ToNumber on a nonprimitive that's not a string, or not an undefined, or a boolean or whatever, when we use it in an object, remember it evokes the ToPrimitive with the number hint.
[00:02:58]
And if you recall, that consults first the valueOf, and then it consults the toString. So what does that look like? Well, for any array or object, by default, meaning you have not overridden these, the valueOf method essentially just returns itself. It essentially does this, return this. Which has the affect of just ignoring the valueOf and deferring to toString.
[00:03:22]
So it doesn’t even matter that the hint was number. It just goes directly to the toString. You can think of the numberification of an object as, essentially, the stringification of it. It's that it's gonna end up producing whatever toString or valueOf produces. That's a perplexing choice, but it's the choice nonetheless, is that it's gonna actually produce a primitive string.
[00:03:47]
So then in your various operations where you were expecting a primitive, but you wanted a primitive number, there's actually a primitive string there. And then further coersions will kick in. So we're gonna end up deferring to the toString and whatever the toString returns. Remember how arrays toStringify themselves without any brackets.
[00:04:06]
So again, we get an array with an empty string in it. When we ToNumber it, it ends up as 0, which is nuts. And then the string with 0 in it, becoming 0 makes a lot more sense. And -0 makes a lot more sense. Here's something bizarre. If the array has either null or undefined, it becomes 0.
[00:04:25]
See if you're paying attention. Can anyone tell me why both of those become 0 here?
>> Speaker 2: Not consistent with the rest of the-
>> Kyle: Actually, this is remarkably consistent with the other craziness we've already seen.
>> Speaker 3: Because they first become empty strings?
>> Kyle: They first become empty strings, and then empty string becomes 0.
[00:04:41]
Remember, empty string is the root of all coercion evil, okay? Empty string becoming 0 is the root of all coercion evil, okay? Same thing with that bottom crazy nested array thing, it just becomes an empty string, which then just becomes 0, okay?
>> Kyle: All right, so if you have an object, its toString returns the object.
[00:05:01]
And remember what a stringification of an object by default is, it's that square bracket object object thing. Which is definitely not a representation of a number, so we get NaN. That's actually reasonable. It's dumb, but it's reasonable. If you override the valueOf for some object, you can return whatever thing you want.
[00:05:18]
In this case, you could return 3, and that's the numberification for it.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops