what kind of problem is this fat arrow feature trying to solve ?

Andrea Giammarchi andrea.giammarchi at gmail.com
Wed Oct 2 10:45:22 PDT 2013


first of all thank you all for your answers. In my experience I tend to not
write `var self = this;` or `var that = this;` since the introduction of
bind. Last Aymeric example is indeed part of what I was asking ...
developers like it because they don't have to write `.bind(context)` at the
end neither `function` at the beginning plus the closure or scope might not
be necessary. This is why I've asked if point 3 would be eventually faster
... but again there are few misunderstanding, specially from David. I'll
try to reply inline.


On Wed, Oct 2, 2013 at 12:34 AM, David Bruant <bruant.d at gmail.com> wrote:

> Le 02/10/2013 04:35, Andrea Giammarchi a écrit :
>
>  setTimeout accept extra arguments ... I write JavaScript that uses this
>> feature.
>>
>> `setTimeout(callback, delay, arg1, arg2, argN, evenAnObject);`
>>
> What is "evenAnObject"? It doesn't look like a standard thing:
> http://www.whatwg.org/specs/**web-apps/current-work/**
> multipage/timers.html#**windowtimers<http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#windowtimers>



`evenAnObject` is a way to solve the "frozen" state of passed arguments.
For those non familiar, `setTimeout` and `setInterval` accepts extra
arguments by W3C standard.
http://www.w3.org/TR/2011/WD-html5-20110525/timers.html#timers

This is working in every single ES3 JS engine you can try (even very old
one) with the nice exception of IE < 10.
However, this code will address exclusively those IE < 10 browsers and fix
the behavior in there too.

```javascript

/*@cc_on
(function(f){
 window.setTimeout =f(window.setTimeout);
 window.setInterval =f(window.setInterval);
})(function(f){return function(c,t){var
a=[].slice.call(arguments,2);return
f(function(){c.apply(this,a)},t)}});
@*/

```

IE10 and 11 won't execute such comment so you are good with a universal way
to pass arguments. Some example:

```javascript
function alertSum(a, b) {
  alert(a + b);
}
setTimeout(alertSum, 1000, 1, 2);
```
Above code will show 3 after a second. The problem David comes with
variables

```javascript
function alertSum(a, b) {
  alert(a + b);
}
var a = 1, b = 2;
setTimeout(alertSum, 1000, a++, b++);
```
the result will be again 3 because arguments are "trapped by value" at
`setTimeout` declaration.

Accordingly David, to solve this problem you might want to pass an object
and address its properties.

```javascript
function alertSum(o) {
  alert(o.a + o.b);
}
var o = {a: 1, b: 2};
setTimeout(alertSum, 1000, o);
o.a++;
o.b++;
```
The result will be 5 so `evenAnObject` meant you can pass any kind of
value, including an object that could be your context in the function
through bind `setTimeout(fn.bind(ctx), 1000)` or extra argument
`setTimeout(fn, 1000, ctx)` without needing to create both a timed
execution and a new bound object but of course, fn should accept a
pythonish `self` argument.

I hope we are clear here ... the rest ...



>
>
>
>> so fat arrow does not solve much here, I can use self as first argument
>> and I am good.
>>
>> `forEach` and all other arrays accept a second argument
>>
>> `array.forEach(doStuff, boundContextObject);`
>>
>> so fat arrow does not solve a thing in mostly all Array extras.
>>
> Both examples are most certainly design mistakes. It feels absurd that
> every function accepting a function as argument must also have a second
> argument for the |this| value (or even variable number of arguments to be
> passed around). Especially in the ES5 era with Function.prototype.bind.
>

I wasn't talking about how great this approach is, I was rather saying that
it is possible to send a context so design mistake or not, the fat arrow
won't solve anything if not extra operations/oibjects to create promoting a
"reuse nothing" pattern hopefully optimized better than current inline
function, but something I've personally never advocated if operations are
repeated. I create the `forEach` utility unscoped as much as possible and
once per execution lifecycle, so that I can send the context through the
second argument instead of create O(n) times the inline function or the fat
arrow.




> The design mistake is emphasized by the inconsistency in the order of
> arguments in the 2 examples you provide.
> I'm glad Node.js didn't make all async functions accept another argument
> for |this|.
>
>
>  for **DOM** I use handlers as specified by **W3C**
>>
> Since when the DOM is specified by W3C? Must be about 10 years it isn't
> the case anymore</troll> ;-)
> Passing a function directly is standard too.



Thanks for the enlightening troll, I was talking about a technique
developers keep forgetting and ignoring, a technique described here which
is **not a trick** just **standard behavior**
http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener

```javascript
AnyClass.prototype.handleEvent = function (e) {
  // will point to the element where
  // addEventListener was used
  e.currentTarget;

  // will be an instanceof AnyClass
  // the object passed as handler
  this[e.type](e);
};


var handler = new AnyClass;
handler.click = function (e) {
  this.clicked = true; // won't expando in the node
  alert([e.screenX, e.screenY]);
};

document.body.addEventListener('click', handler);

```
Handler could be used for any sort of custom or real event and won't
require any WeakMap to be attached and related to any DOM node.

Once again, this is the best pattern for state-machine like DOM behavior
and developers keep creating 234567890 bound functions instead forgetting
that simply using a different approach they could both solve and speed up
many things at once.

This behavior is perfectly normalized in IE8 too, the only browser that
does not have `addEventListener` and friends, through this ie8 library:
https://github.com/WebReflection/ie8

Today, you could start writing a simplified and better approach to DOM <=>
JS interactions.





>
> But "won't be able to remove later on" is false:
>
>     document.addEventListener('**DOMContentLoaded', function dcl(){
>         // whatev's
>         document.removeEventListener('**DOMContentLoaded', dcl);
>     });



You didn't use a fat arrow because indeed you cannot use one unless named
and its name is available so ... what is your point here?

The fat arrow will inevitably lead to patterns such:

`document.addEventListener('eventName', (e) => e.stopPropagation());`

where it's impossible to get rid of that later on if needed (remember the
statemachine approach? I could redefine entire behaviors simply adding or
removing a single object ... won't be possible with fat arrows all over)

Even worst, that pattern could lead to this obscenity:

```javascript
let fn;
document.addEventListener('once', fn = (e) =>
e.currentTarget.removeEventListener(e.type, fn));
```

WAIT, WHAT? Actually, we have a problem with the DOM.

First of all the `this` will be the one at fat arrow function definition
time, so that the node must be retrieved through `e.currentTarget` which
means that every single framework that relies in `this` should be somehow
updated if fat => arrow is desired.

So, one of the major benefits of `addEventListener` compared with
`attachEvent` is gone, `this` in the wild, most likely always `window` or
`undefined` under `use strict` directive.

So here my question: is fat arrow solving anything in this case? My answer
is no.



>
> I understand that in some cases, specs allow to pass |this| or additional
> arguments, but it doesn't make it a good idea. I see the fact that Node.js
> didn't take that road as a very strong signal.
>
> David
>

node.js has been lucky enough to born in an era where
`Function.prototype.bind()` was already there otherwise would have came up
with a similar solution.

That said, node.js also broke completely interoperability with any DOM
Event we know since 1999 thanks to the (in?)famouse double argument pattern
with the nullish error as first argument.

Not everything chose there is good neither but I agree, it would have been
ugly to put a final context argument to each class method.

Best Regards
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20131002/7546c11c/attachment-0001.html>


More information about the es-discuss mailing list