(coughs) Okay. So coercion. Big hairy topic. We're gonna try to break it down piece by piece. The first thing that I'll observe about coercion is that the way it happens is from one value type to another value type. That's what coercion means when we've got one value type and something requires it to be represented in a different value type. The way that happens from the perspective of the specification is that we have defined a set of what we call abstract operations.
There's a section called ToString in the spec and I'd encourage you to read it. Rather than getting into all the nuts and bolts of it, I thought I'd illustrate it for you several examples of things that are fairly reasonable except for maybe the last line. These are all fairly reasonable but if we start out, for instance, with the null value and we call the ToString abstract operation on it, in whatever way, shape, or form that ends up happening, if ToString is called against a null value, we get quote null. If ToString is called against an undefined value, we get quote undefined.
True, false, 3.14159, zero. Those are all reasonable results of the ToString operation. Negative zero here still ends up giving us that quote zero and that is because the ToString operation literally says return quote zero. Basically lie to them and pretend that it's zero. If there were to be something I would fix about the language to make it more accurate and not lying to me, I'd fix that. I'd tell ToString don't do that.
If I've got a negative zero, just give me a negative zero. I will swallow that pill because I would rather it be accurate than lying to me. It's not something that I'm ever gonna be likely to change. So this is pretty reasonable. So far ToString behaves kind of like we would expect. What happens if we called ToString on an object? Like a function or an object or an array? Well, then it will invoke the ToString method.
Sort of. It invokes the ToString method if it's there and if it's not, then it does some other stuff. It actually invokes this thing called ToPrimitive which we'll get to in a moment. For our intents and purposes, if you call the abstract operation, ToString, if you tell an object, array, or function to stringify itself, it's gonna look and see if that object, array or function has a ToString method and if it does, it's going to invoke that ToString method. That ToString method could be the one that's built in or it could be one that you end up defining your own.
You can make your own on your objects. It'll use whichever one that's either built in or the one that you've used or the one that you've created if you created one. Guess what happens if you do something evil like create a ToString method for some value but you return something non-string from it. That would be stupid and evil but you can do that. You can create your own ToString method for some object and have it return the number 42.
To me, that is infinitely more reasonable than leaving the brackets off. I do not understand why they thought the stringification of an array ought to leave the brackets off as if to somehow pretend that this thing wasn't an array. For example, I don't show it here, but if I had bracket one, an array with a single value in it of the number one and I did a stringification on that, I'd do ToString on it, I'd get quote one which would leave me with no information whatsoever that the thing that I just stringified was actually an array.
I think this is a dangerous mistake that they made a long time ago. It's very difficult to conceive a way that they can fix this but it's something to call out. The stringification for arrays, in my opinion, is broken. It's broken mostly because it doesn't put the brackets there. It's also broken because look at the second line. It doesn't stringify null and undefined the way null and undefined themselves stringify. W-T-F. I can't fathom. I wasn't there.
So essentially that fourth comma on that last line there, that fourth comma is not actually taken to be showing that there is a member of the array. You might think that that would imply that there's five elements in the array 'cause four commas, there's five slots there. It actually means that there's four elements and then a trailing comma that gets ignored. It's weird but that's an ES5 rule that trailing commas are allowed and then ignored. That actually ends up creating an array of four empty elements or four empty slots rather than five.
Which is completely and totally unhelpful, in my opinion. If you try to stringify an object, why doesn't it behave even remotely like the JSON stringification does? Even if it was somehow close. Even if it just did what arrays did, that would be better than this object Object thing with the bracket around it that looks like it's an array. That's nonsense. I wish I could fix it but now I'm just the messenger. I'm reporting how these things work. So stringification of arrays and objects.
They'll strip out all the comments and white space and anything else that you might have seen. Some engines just leave the functions straight up as is. There are people that try to do parsing of function stringification and do weird stuff like that. They require JS and some of those others. They try to do some of that funky stuff. It's not standard and I think it's kind of like going into the wild. It's like username. It's like user-agent parsing. You're venturing into the wild wild west if you start trying to do that stuff. I'd avoid function stringification if I were you but it is definitely there.
Note: This course was created by Frontend Masters. It was originally released on 8/29/2015. We're pleased to host this training in our library.
- Primitive types: undefined, string, number, boolean, and object
- Special values: NaN and negative zero
- Natives: Regex and date
- Functions: toString, toNumber, and toBoolean
- Implicit coercion
- Explicit coercion
- Strings, numbers, and booleans
- Operators: Double equal and triple equal