tag:blogger.com,1999:blog-22367266.post5677038977010307200..comments2023-07-04T09:16:12.941-04:00Comments on pmuellr: bind() considered harmfulPatrick Muellerhttp://www.blogger.com/profile/04900886008475308281noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-22367266.post-17708211251084953432010-07-24T08:54:42.444-04:002010-07-24T08:54:42.444-04:00> Define "pointing to".
I meant the ...> Define "pointing to".<br /><br />I meant the link in Web Inspector ("bind_vs_closure.html:10" in my example) is pointing to the line number where the bound function was created.<br /><br />> I think I'd rather that bound functions have some new special property that points to the original function. In the spec, it's the [[TargetFunction]] internal property, but internal properties aren't "real".<br /><br />I suppose [[TargetFunction]] might be accessed within Web Inspector's back-end. I hope so.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22367266.post-20122389323752644862010-07-20T18:34:59.837-04:002010-07-20T18:34:59.837-04:00> The bound function is pointing to the Functio...<i>> The bound function is pointing to the Function.prototype.bind, which isn't very helpful. For me, that's the main problem of prototype.js-like bind. I'm pretty sure native `bind` won't have this problem.</i><br /><br />Define "pointing to". All property accesses on the bound function delegate to the original function? I don't think that's what the spec says (my current understanding), and I'm not sure that's the right thing to do anyway. <br /><br />I think I'd rather that bound functions have some new special property that points to the original function. In the spec, it's the [[TargetFunction]] internal property, but internal properties aren't "real".Patrick Muellerhttps://www.blogger.com/profile/04900886008475308281noreply@blogger.comtag:blogger.com,1999:blog-22367266.post-24527572331918195782010-07-20T12:23:46.224-04:002010-07-20T12:23:46.224-04:00kangax,
1) It's not just about `toString`. Lo...kangax,<br /><br />1) It's not just about `toString`. Look at http://elv1s.ru/files/js/bind_vs_closure.png and http://elv1s.ru/files/js/bind_vs_closure.html<br /><br />The bound function is pointing to the Function.prototype.bind, which isn't very helpful. For me, that's the main problem of prototype.js-like bind. I'm pretty sure native `bind` won't have this problem.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-22367266.post-36646720560861538472010-07-19T18:10:18.102-04:002010-07-19T18:10:18.102-04:00kangax,
1) bind being "anonymous"; see ...kangax,<br /><br />1) bind being "anonymous"; see the previously mentioned bug report by NV, which modify's the toString() method of the bound function for Web Inspector's internal code (doesn't help anyone but Web Inspector developers). For debug purposes, it might be nice if there was a "standard" for the toString(), or even better, or if there were a way to introspect over these bound functions. <br /><br />2) You caught me, I hadn't fully read and/or understood the spec. Not sure I understand all the ramifications of it yet. But you're right, no new scope is created by just creating the bound function. Even in the case of libraries (jQuery, Dojo, etc) implementations of bind(), the scope is going to be container to that of the bind() implementation, which shouldn't be leaky, but it's something.<br /><br />Of course, you just know we'll start seeing:<br /><br />el.addEventListener('click', (function(){ <br /> console.log("in a click handler: " + this)<br />}).bind(this), false);<br /><br />which puts us back in leaky closure mode :-)<br /><br />I finally caught up on JavaScriptCore's <a href="https://bugs.webkit.org/show_bug.cgi?id=26382" rel="nofollow">Bug 26382: [ES5] Implement Function.prototype.bind</a>, and there's some interesting bits in there about the eventual implementation, for folks interested in this stuff. Most interesting was realizing the shortcuts they planned on making, which didn't seem to safe to me at the time, but makes more sense now.<br /><br />I happen to be watching the bind() implementation.<br /><br />3) 'longish' isn't a terribly strong argument, blame Alex for that one :-) DRY is nice though, as in not having to repeat obj twice in the "obj.method.bind(obj)". This would be somewhat offset if the common case for "obj" is "this", leaving us with "this.method.bind(this)" is at least something that you can cut+paste around safely, assuming that's the style you're using for your code.<br /><br />4) w/r/t this is at least one type of garbage I was referring to - the newly returned function itself.Patrick Muellerhttps://www.blogger.com/profile/04900886008475308281noreply@blogger.comtag:blogger.com,1999:blog-22367266.post-1761094218761656432010-07-19T17:10:41.487-04:002010-07-19T17:10:41.487-04:00NV, see Kangax's point #2.
Thanks for the &qu...NV, see Kangax's point #2.<br /><br />Thanks for the "dirty hack" on <a href="https://bugs.webkit.org/show_bug.cgi?id=40080" rel="nofollow">bug 40080</a>; I haven't had a chance to use it, but will soon. Have you found it to be helpful?Patrick Muellerhttps://www.blogger.com/profile/04900886008475308281noreply@blogger.comtag:blogger.com,1999:blog-22367266.post-91757695612697669462010-07-19T16:58:16.193-04:002010-07-19T16:58:16.193-04:00More stuff on eventHandler recently published on A...More stuff on eventHandler recently published on Ajaxian: <a href="http://ajaxian.com/archives/an-alternative-way-to-addeventlistener" rel="nofollow">http://ajaxian.com/archives/an-alternative-way-to-addeventlistener</a>Patrick Muellerhttps://www.blogger.com/profile/04900886008475308281noreply@blogger.comtag:blogger.com,1999:blog-22367266.post-70244354182797865662010-07-17T23:56:38.885-04:002010-07-17T23:56:38.885-04:00Interesting thoughts, Patrick.
I have few comment...Interesting thoughts, Patrick.<br /><br />I have few comments:<br /><br />1) Saying that `bind` gets in a way of debugging is similar to saying that anonymous functions get in a way of debugging. This is a valid argument of course, but it's something debuggers/profilers can relatively easy take care of. As you might know, `Function.prototype.toString` is specified to return implementation-dependent representation of a function (in both ES3 and ES5); Nothing is stopping implementations from returning source of original function prepended with something like [Bound function] and maybe also [Target function: ...], [Bound arguments: ...], etc.<br /><br />2) I don't understand the "garbage" argument. I'm not sure why you think that closure is formed on creation of bound function. There is no change in scope of the function that gets bound to an object (and/or arguments). ES5 even explicitly states that bound function — contrary to regular native function objects — doesn't have [[Scope]] (internal property which is a reference to a lexical environment in ES5 and scope chain (list of activation objects) in ES3). In ES5 `bind` merely creates a wrapper object (that's made to look almost like a function object). This wrapper delegates invocation (`()` operator, internal [[Call]] method), instantiation (`new` operator, internal [[Construct]] method) and property existence check (`in` operator, internal [[HasInstance]] method) to an original (target) function. No change of [[Scope]] of target function is ever made and no [[Scope]] is ever created on a bound function.<br /><br />Now compare this to a popular replacement of `bind` — creating a wrapping function:<br /><br />el.addEventListener('click', obj.method.bind(obj), false);<br />el.addEventListener('click', function(){ obj.method(); }, false);<br /><br />In a second example, wrapping function DOES in fact have a scope and a closure DOES get formed. Now, speaking of garbage, imagine if this second snippet was buried somewhere deep inside bunch of other code and how much garbage handler function would close over (pretty common case, imo):<br /><br />(function(){<br /><br /> // ... some code and variables<br /> (function(){<br /> <br /> // ... some more code and variables<br /> el.addEventListener('click', function(){ <br /> <br /> // all the variables from the enclosing scope <br /> // are now closed over in this function<br /> <br /> obj.method();<br /> }, false);<br /> <br /> })();<br />})();<br /><br />When compared to wrapping-function bind replacement, I would think that `bind` makes for a more performant code, not the other way around.<br /><br />3) Longish to type argument is a bit weak, in my opinion.<br /><br />This is how we used to do things:<br /><br />el.addEventListener('click', function(){ obj.method() }, false);<br /><br />And this is how we can do it with bind now:<br /><br />el.addEventListener('click', obj.method.bind(obj), false);<br /><br />`bind` one is shorter. And it avoids creation of closure too. It's a win/win :)<br /><br />Of course, `el.addEventListener('click', obj, 'method', false)` would be even shorter, but then you end up with 4 arguments and that's already something begging for "too many arguments" type of refactoring :)<br /><br />4) The point about `bind` retuning new function every time — and that being "bad thing" — is interesting. I can see how it's inconvenient in case of `addEventListener`/`removeEventListener` (although in context of browser scripting, it's recommended to avoid frequent removal of listeners in favor of delegation).kangaxhttp://perfectionkills.com/noreply@blogger.comtag:blogger.com,1999:blog-22367266.post-71117668936232344572010-07-11T16:29:04.284-04:002010-07-11T16:29:04.284-04:00What I proposed on bug 40080is a dirty hack. It he...What I proposed on <a href="http://webkit.org/b/40080" rel="nofollow">bug 40080</a>is a dirty hack. It helps a very little with debugging, but doesn't fix other problems you have mentioned.<br /><br />Instead of <br />node.addEventListener("click", obj.callback.bind(obj))<br /><br />I usually do<br />node.addEventListener("click", function(){ <br /> obj.callback();<br />});<br /><br /><br />An example:<br /><br />var obj = {<br /> func: function(){console.log(this.n)},<br /> n: 1<br />}<br /><br />document.addEventListener("click", function clicked(){<br /> obj.func()<br />}, true)<br /><br /><br />I don't see any benefits in your proposal. What it does, what my version above can't do? Am I missing something?Anonymousnoreply@blogger.com