There are two ways to think of type coercion in JavaScript. One is to the dictionary definition, which is the conversion of values into common data types to facilitate operations like comparison. The other, is the things JavaScript does to make you like it.
I used to wonder why the word "Coerce" was used. Wouldn't it make sense if we called it Type Conversion? But there is something in the nature of this process that implies a brutal conversion. JavaScript does not simply convert a string into a Boolean, how could it? Instead, it beats the shit out of it into a Boolean. The value is barely recognizable at the end.
Type coercion is not unique to JavaScript but the wonky behaviors in JavaScript made it all too popular. You probably saw bloggers ranting about it to prove how much JavaScript suck.
"" == false // true
" " == false // true
"hello" == true; // false
" " == 0; // true
"0" == 0; // true
0 == false; // true
"0" == false; // true
[] == []; // false
I randomly typed those above, and to tell you the truth, I couldn't predict what was going to come out. But that's OK, because I never type this in my code anyway. Never! It's like ranting about how the car engine behaves when you put water in it instead of gas.
Remember that type coercion only happens when you use non-strict comparison operators. It doesn't happen with ===
or !==
.
What is Type coercion doing anyway?
If you come from a language that has type casting you will understand better.
// PHP
$pagenumber = (int) $_GET['page']; // 0 if it fails
// Java
Object o = "Hello world";
String str = (String) o;
Here the compiler does its best to convert the values with one type to another. In Java, if it fails you get a big giant error. In the PHP example, if it fails, it gets a default value for the data type.
Inside JavaScript, there are a few things that go on before ("0" == false)
is evaluated. Let's break it down.
The data types in JavaScript are Number, String, Boolean, Undefined, Null. Before any comparison happens, the compiler checks if your values are coercible (using CheckObjectCoercible).
There are a series of conversions that are available and JavaScript chooses the best for the situation:
ToPrimitive
Here the goal is to have a non-object type result. There is conversion only if our value is an object, and it will result in a bare-bone data type listed earlier.
ToBoolean
Null and undefined are automatically set to false. Boolean values are taken at face value. Numbers are set to false if they are positive 0, negative 0, or NaN.
ToNumber
Undefined becomes a NaN. Null turns into a positive zero. For booleans, true becomes 1, false becomes zero. Numbers are not converted. Strings go through a complex process to determine the most appropriate value. If a good value still can't be found, then the value NaN is set. For objects, ToPrimitive is called first to get a default value before the attempt to convert it to a number.
ToString
Undefined becomes "undefined", Null becomes "null". true becomes "true", false becomes "false". Numbers get a special treatment, think of 10e3
. Converting it to "10e3" would be incorrect, so it becomes "10000". For object ToPrimitive is called before the final conversion.
There are some conversion methods I didn't include — ToObject, ToInteger, ToUint32, ToUint16 — but you get the idea now. So how does all this apply to our little condition?
("0" == false)
are of two different data type. To make it match, the Runtime will convert the ambiguous "0" string to a number, which will be equal to zero. False can also be converted to a number, remember ToNumber(false) is 0.
Now the Runtime has two values that have the exact same data type. The comparison will be: (0 == 0) which results to true.
You might be saying, "OK that make sense. But how about [] == [], why is this false?" This doesn't have to do with Type coercion. These are objects, of the same data type. The only difference between the too is that they have 2 different memory address.
a = [];
b = [];
a == b; // false;
// however,
a = []
b = a;
a == b; // true; // they are pointing to the same object in memory
a === b; // true;
b.push(1);
b; // [1]
a; // [1]
I hope this make sense now.
Back to type coercion. If I was to tell you to memorize all this behavior of JavaScript, I'm sure you will say "Yuck!" Luckily, JavaScript has good parts. And you almost never have to deal with type coercion.
Just make sure you know what type of value you are expecting and you are set. Use the triple equal sign to avoid type coercion all together.
When you are getting user input from a form, make sure you convert it to the correct values first before using it.
<form name="myform">
<input type="text" placeholder="How old are you" name="age"/>
</form>
// JS
// document.myform.age; // is a string
var age = parseInt(document.myform.age,10);
if (isNaN(age) === true) {
alert("Wait a minute, you are saying your age is not a number?");
return;
}
if (age === 24) {
alert("Fine we will let you rent a car");
}
This is a simple example but even as your application grows with complexity you can still apply the same methods.
If you don't want to memorized all the behavior of type coercion, make sure you always use ===
and !==
instead. Otherwise, brew some coffee and start reading all of ECMAscript Language Specification.
I hope you have learned a thing or two about type coercion.
Resources:
- Ecma-262: Ecmascript 5.1 approved Candidate, See #chapter 9.
Sign up for the Newsletter.
Comments
There are no comments added yet.
Let's hear your thoughts