Coercing objects to primitives

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:

  • valueOf()

  • toString()


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:

  • Stay away from instances of Boolean, Number and String. You don’t normally need or encounter them in JavaScript.

  • However, I do like using Boolean, Number and String as functions, to coerce values. They are nicely descriptive when used in this manner.

  • Obviously, all of the above ways of coercing to primitives work for any value, not just for objects:

    > Number("123")
    123
    > Boolean(0)
    false
    > String(true)
    'true'


  • One does not often coerce objects to primitives. Doing so is, however, good for many WTFs [1] and hacks [2].



Further reading




  1. What is {} + {} in JavaScript? [Describes the binary plus operator and the conversion to number and string in detail]

  2. Fake operator overloading in JavaScript [a fun hack involving objects being coerced to numbers]

  3. JavaScript’s two zeros


Comments

Popular posts from this blog

Steve Lopez and the Importance of Newspapers

Ideas for fixing unconnected computing

Omar to kill me