arrow function syntax simplified

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Apr 2 18:57:16 PDT 2012


On Apr 2, 2012, at 4:22 PM, Jorge wrote:

> On Apr 2, 2012, at 9:47 PM, Brendan Eich wrote:
>> Douglas Crockford wrote:
>>> 
>>> 
>>> It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.
>> 
>> (...)
>> 
>> I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.
> 
> I was chatting this evening with a friend about this (ruby) thing:
> 
> class Numeric
>  (Math.methods - Module.methods - ["hypot", "ldexp"]).each do |method|
>    define_method method do
>      Math.send method, self
>    end
>  end
> end
> 
> 
> And I showed him how one could do that easily in JavaScript:
> 
> Object.getOwnPropertyNames(Math).forEach(function (key) {
>  if (typeof Math[key] === 'function') {
>    Number.prototype[key]= function () {
>      return Math[key](this);
>    };
>  }
> });
> 
> 

Of course this is a very specialized transfer in that you need to remap functions (that don't reference this) into a method that does.  Essentially you are creating a wrapper method that calling a function passing the method's this value as an argument to the function all.  This isn't like a normal object composition (eg "Object.extend" ) where you are just method references from one object to another. In this case you have to know how to make each function.  You can do this because you know that every function valued property follow the same form and can use the same mapping pattern.  i suspect that this is not a very common situations.  Normally the methods you are transferring probably won't be this regular. or will have other issues (such a super reference) that would probably require you to use slightly different techniques such as Object.defineMethod.

Object.getOwnPropertyNames(Math).forEach(function (key) {
 if (typeof Math[key] === 'function') {
   Object.defineMethod(Number.prototype,key,function () {
     return Math[key](this);
   });
 }
});

Bottom line, I'm not use that this really represents a very common scenario...

> Then I thought, let's see how would that look like with arrows ?

But that would be wrong assume that arrows always lexically bind this.  

> 
> 
> Object.getOwnPropertyNames(Math).forEach((key) => {
>  if (typeof Math[key] === 'function') Number.prototype[key]= () => Math[key](this);
> });
> 

To define a method you really need to use either a function definition (as in your original snippet) or alternatively a concise method in an object literal:

Object.getOwnPropertyNames(Math).forEach((key) => {
 if (typeof Math[key] === 'function') Number.prototype[key]= {m() {return Math[key](this)}.m;
});

This suggests that we might benefit from defining Object.defineMethod in a way that leverages concise method syntax:

Object.getOwnPropertyNames(Math).forEach((key) => {
 if (typeof Math[key] === 'function') Object.defineMethod(Number.prototype,key, {method() {return Math[key](this)});
   //if method arg is a non-functjon object use the value of its property named 'method'
});


> And it turns out that here, the outer/enclosing context `this` isn't the one you want/need. You'd need a dynamically bound `this` instead:

yes, but the root problem is trying use an arrow functions to define a method.  Based upon these examples I'm inclined to think that Object.defineMethod should throw if the value it needs to install is a arrow function value.

> 
> Object.getOwnPropertyNames(Math).forEach((key) => {
>  if (typeof Math[key] === 'function') Number.prototype[key]= (this) => Math[key](this);
> });
> 
> and thus the this-in-the-parameters-list trick.
> 
> I don't think it's such a rare case: Inside a constructor function called with `new`, yes, `this` is most likely going to be the right `this` always, but when you are building objects with a factory (e.g. with a .create() method), the enclosing `this` usually isn't going to be the right one.

When you are building objects with a factory as you are describing you are presumably taking methods that were defined using an object literal or some other property method definition pattern:

let obj = mayFactory (arg) {
  return Object.extend({x:arg}, {
      method1() {...this...},
      method2() {...this...},
      ... /etc,
    });
};

The second argument to Object.extend might have been define remote but is likely still to be a template object with property dynamic this bound methods.  I think the sort of this to argument remapping you show is actually pretty unusual. 

Allen







> -- 
> Jorge.
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> 



More information about the es-discuss mailing list