In the previous article I talked about types and type coercion in JavaScript. In this one I want to talk more about how this coercion applies to JavaScript operators. Lets go over six major operators and look at how they work:
typeof
The typeof operator returns a string representation of the type of the passed expression. There are two major points to note:
- Unresolvable references will produce
"undefined", i.e.typeof awill return"undefined"if variableawas not declared. typeoflies in two cases fornulland forfunction () {}.
Apart from this, operator works pretty much as a lookup table:
| Type of expression | Result |
|---|---|
| Undefined | "undefined" |
| Null | "object"⚠ |
| Boolean | "boolean" |
| Number | "number" |
| String | "string" |
| Object, that can’t be invoked | "object" |
| Object, that can be invoked | "function"⚠ |
I marked with “⚠” two places where operator is misleading: type of null is Null and the actual type of any function is Object.
Subtraction
Converts both arguments to number. "8" - true is converted to 8 - 1. Very simple, indeed. Don’t expect the same from addition
Addition
Addition is one of the trickiest operators in JavaScript. Lets see what is going on when you write a + b:
- Both arguments are converted to primitives. Lets call them
AandB. - If any of primitives is a String, concatenate
AandBas strings. - Otherwise add
AandBas numbers.
For example:
8 + "5" ➙ "8" + "5" ➙ "85"; 8 + true ➙ 8 + 1 ➙ 9; "8" + true ➙ "8" + "true" ➙ "8true";
Less-than
In contrast to the addition operator, the less-than operator compares arguments as strings only if both of them are strings. To put it more formally, here are the steps:
- Both arguments are converted to primitives. Lets call them
AandB. - If both of primitives are Strings, compare
AandBas strings. - Otherwise compare
AandBas numbers.
For example:
8 > "5" ➙ 8 > 5 ➙ true; 8 > true ➙ 8 > 1 ➙ true; "8" > "18" ➙ true;
Strict Equals
The favourite operator of many, also known as triple equal (===) does things in a very simple way: checks if the arguments are of the same type and if they are, checks if they are equal. His little brother has a little bit more complicated character.
Equals
Ok, here it comes, the most hated operator of the language. According to the spec it works like so:
- First check for types, if they are the same, apply strict equals.
- If both arguments are either
nullorundefined, returntrue. - If one of them is String and the other is Number, convert both to Number and apply strict equals.
- If one of them is Boolean, convert it to Number and go to 1.
- If one of them is String or Number and the other one is Object, convert object into primitive and go to 1.
- Return
false.
This basically means that equals works like less-than, when the types of the arguments are different and like strict equals, when types are the same. The easy way to remember: when the types are different it converts both arguments into primitives, then into numbers, unless they both are strings. Oh, and null == undefined is true.
8 == "5" ➙ 8 == 5 ➙ false;
1 == true ➙ 1 == 1 ➙ true;
0 == "" ➙ 0 == 0 ➙ true;
0 == "0" ➙ 0 == 0 ➙ true;
"" == "0" ➙ false;
"1000" == "1e3" ➙ false;
1000 == "1e3" ➙ true;
5 == {valueOf: function () { return 5; }} ➙ 5 == 5 ➙ true;
These are not all the operators, but certainly the most tricky ones.
September 24, 2012 at 3:53 pm, Tobie Langel said:
The major gotcha of the
typeofoperator which you didn’t mention is that it also returns"object"for arrays.September 24, 2012 at 4:00 pm, Dmitry Baranovskiy said:
It returns
"object"forRegExp,Dateand others too. It does make sense, but I agree having it return"array"for arrays would be useful.November 06, 2012 at 2:36 am, Durgesh said:
But the arrays are just wrapper over the object. Please correct me If I am wrong.
September 24, 2012 at 10:17 pm, Mikhail Davydov said:
You mention valueOf, but not say that this is the part of object ToPrimitive convertation. And depend on the second argument (hint passes) object converts to primitive using (valueOf || toString)() or (toString || valueOf)(). It may also throw an TypeError if both of them are not callable.
http://jsfiddle.net/Sm8dT/
Arrays with > are funny too
September 24, 2012 at 10:29 pm, Dmitry Baranovskiy said:
I mentioned
valueOf&toStringin the first article.September 25, 2012 at 7:13 am, Alexandr Subbotin said:
… but not when both arguments are NaN, because NaN !== NaN