Function.prototype.bind

David-Sarah Hopwood david.hopwood at industrial-designers.co.uk
Wed Sep 10 17:37:25 PDT 2008


Brendan Eich wrote:
> On Sep 10, 2008, at 10:15 AM, David-Sarah Hopwood wrote:
> 
>> However, unlike what I proposed, 'strawman:lexical_scope' doesn't make
>> the bindings of the primordials that are visible when it is active
>> deeply immutable. I suppose that's difficult if you want the
>> prototypes to appear to be the same between code that is in such a
>> block and code that is not -- for instance, '"" instanceof String'
>> should work whether or not 'String' refers to a deeply immutable or
>> mutable constructor.
> 
> Right. Also, people mutate standard objects, whether it's a good idea in
> the large or not. The "use lexical scope" idea is not meant to break
> compatibility on that point.
> 
> It's rarer (although still done -- see
[https://bugzilla.mozilla.org/show_bug.cgi?id=409252#c4])
> for web JS to mutate the global bindings for Object, Date, etc.

ECMA-262 is entirely unclear about what effects that is supposed to have,
and it did different things between implementations (for example FF2 used
shallow binding of at least Array, while IE7 mostly ignored changes to
these bindings). So if there is any code relying on doing this, at best
it worked by accident.

I see only references to rebinding of 'Date' in that bug report (and
'Namespace' which is not relevant to ES3.1). The semantics of rebinding
Date are much clearer than they are for constructors that are implicitly
accessed as a result of evaluating literals (Array, Function, Object,
String and RegExp). In particular, there are intractable bootstrapping
issues in specifying what it should mean to rebind 'Object' or 'Function',
at least. Furthermore, allowing rebinding of these implicitly accessed
constructors could inhibit useful optimizations, while I assume no-one
really cares about optimizing Date.

So here is my strawman proposal:
 - leave 'Date' Writable in the global scope;
 - make Array, Function, Object, String and RegExp non-Writable and
   non-Configurable, unconditionally;
 - make Array, Function, Object, String and RegExp not declarable as
   variable names;
 - make all of the new "static" methods on Array, Function, Object
   and String non-Writable and non-Configurable, unconditionally.

This will not break Ajax library code that tries to install compatible
implementations of these new methods, because:

 - if that code is running in non-strict mode, the attempted updates
   will be silently ignored.
 - if it is running in strict mode, then it must be new code that
   knows to catch the resulting exception.

Note that the Array, Function, Object, String and RegExp constructors
would not be sealed, and the prototypes would still be mutable. So this
proposal is not attempting to address the secure sublanguage issues
(at least not on its own), only the issue with self-hosting.

With this design, it's no longer necessary to worry about rebinding
or shadowing in the self-hosting specifications, *or* in the expansions
of new syntactic sugar, provided that they only use the static methods
and do not use Date. I do not believe that anything important on the web
will break as a result of these changes -- and if it does, then I think
it desperately needed to be broken as soon as possible.

The self-hosting specification of Function.prototype.bind would be:

  Object.defineProperty(Function.prototype, 'bind', {
    writable: false, enumerable: false, configurable: false, value:
    function(self, var_args) {
      const thisFunc = this;
      const leftArgs = Array.slice(arguments, 1);
      return function(var_args) {
        const args = Array.concat(leftArgs, Array.slice(arguments, 0));
        return Function.staticApply(thisFunc, self, args);
      };
    }
  });

(no 'use lexical scope' needed).

> Could you suggest a new name for Function.apply (and the static bind and
> call, for that matter)? Thanks,

I suggested apply3 and call3 in a previous post, but on second
thoughts I'd like to change that to staticApply, staticCall and
staticBind. The '3' doesn't work for call or bind because they take
variable arguments, and it's ugly even for apply.

-- 
David-Sarah Hopwood


More information about the Es-discuss mailing list