Bug fix and clarification: What does "({}).valueOf.call(3)" return?

Mark S. Miller erights at google.com
Sun Feb 22 20:06:27 PST 2009

In ES3, ({}).valueOf.call(3) returns a newly wrapped 3, and does on at
least FF, Safari, and Opera. According to the present ES3.1 draft, it
returns the unwrapped primitive 3. This is merely a mistake. We have
previously agreed verbally, both on the ES3.1 phone calls and at one
of the recent ECMAScript meetings that the Ch15 methods should, to
preserve their current wrapping behavior, be speced to ToObject their
this argument when this would make a difference. As a result,
({}).valueOf.call(3) would still evaluate to a newly wrapped 3 on
ES3.1 as well.

In talking to Allen recently, I realized that it may not have been
clear to everyone what observable difference remains after making this
fix. In ES3, ({}).valueOf.call(null) returns the global object. In
ES3.1 it would not and must not, since if it did, all the safety
provided by ES3.1-strict (against privilege escalation via ambient
access to the global object) would be for naught. This issue applies
to many Ch15 generic methods, but affects *only* their behavior when
their call/bind/apply method is called with null or undefined as their
first argument.

valueOf was the only one I knew of that returned direct access to the
global object. Allen also came up with [].concat.call(null). But
giving direct access to the global object isn't the only issue. Many
of the generic methods in Ch15 side effect their this. In ES3,
[].sort.call(null) would sort the global object. If the global object
may be arbitrarily side effected by code without access to it, we're
also sunk.

I think this decision is the right and necessary one. But if, as seems
to be the case, the implied minor upwards incompatibility was not
generally appreciated, we need to check that we indeed have consensus
on this decision.


More information about the Es-discuss mailing list