This blog post looks at how JavaScript coerces objects to primitives. If you don’t know the difference between primitive values and objects, I suggest you consult my article “
Categorizing values in JavaScript” at the Adobe Developer Connection.
This post was triggered by the
following tweet by David Bruant:
!!(new Boolean(false)) #wtfjs
The result of the above expression is
true. Let us first learn about
coercion in JavaScript. We can then use that knowledge to understand this result.
Coercion
Many operators and functions in JavaScript expect their arguments to have certain types. If they don’t, they are
coerced (converted) to those types.
Coercing an object to a primitive type is a two-step process: First, the object is converted to a primitive. Then, if necessary, the primitive is converted to the correct type. Two methods are used to convert an object to a primitive:
There are three conversion algorithms:
- “Number”: you expect the value to be a number.
- “String”: you expect the value to be a string.
- “Default”: you don’t have any expectations for the value.
The number algorithm first calls
valueOf() and uses the returned value if it is primitive. Otherwise, it calls
toString() and uses its value if it is primitive. Otherwise, an exception is thrown. The string algorithm calls the methods in reverse order. The default algorithm is “number” for non-dates and “string” for dates.
Let’s try out coercion via the following object:
var obj = {
valueOf: function () {
console.log("valueOf");
return '0';
},
toString: function () {
console.log("toString");
return 1;
}
};
Coercing to number
There are two common ways for coercing to number: the unary plus operator and
Number, used as a function (not as a constructor).
> +obj
valueOf
0
> Number(obj)
valueOf
0
In both cases, things work as expected: the number algorithm is used. Then the result returned by
valueOf() is converted to number.
Coercing to string
Two common ways of coercing a value to string are: the binary plus operator where one operand is a string and
String, used as a function (not as a constructor).
> ''+obj
valueOf
'0'
> String(obj)
toString
'1'
The binary plus operator uses the default algorithm, because one can add either numbers or strings.
Coercing to boolean
Two ways of coercing to boolean are: using the unary negation operator twice (once converts to boolean and negates) or using
Boolean as a function.
> !!obj
true
> Boolean(obj)
true
Here we see that objects are never converted to primitive. The rule is simply: any object is always
true. For primitives, only the following values are coerced to
false, all other values are coerced to
true.
- undefined
- null
- false
- +0, -0, NaN
- ""
Understanding the initial result
Now it should be obvious why
!!(new Boolean(false)) evaluates to
true: Any instance of
Boolean is always an object and those are always coerced to
true.
Recommendations
Here are a few recommendations for coercion and objects:
Further reading
- What is {} + {} in JavaScript? [Describes the binary plus operator and the conversion to number and string in detail]
- Fake operator overloading in JavaScript [a fun hack involving objects being coerced to numbers]
- JavaScript’s two zeros