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 <bruan...@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
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss