On Sat, 11 Oct 2008 at 22:58:32, in comp.lang.javascript, Conrad Lender wrote:
>On 2008-10-11 21:31, John G Harris wrote: >> Moreover, the language Crockford defines isn't JavaScript, or even >> javascript. It's a language where you aren't allowed to do
>> ... { ... { ... } ... } ...
>Where does he say that?
In the syntax diagrams.
>You're quoting him out of context; JSON wouldn't be possible if nested >curlies weren't allowed.
Perhaps I should have said I wasn't talking about literals.
> Just a guess, but he was probably talking about >the absence of (traditional*) block scope in JavaScript, and was >suggesting that unnecessary {} blocks shouldn't be used, in order to >avoid confusion. In that context, I would agree with Crockford.
He does say that a block is not a scope. What he doesn't say is that a block is also a statement. Whether that's for doctrinaire reasons or from ignorance I don't know.
I don't think he says in words that he doesn't want to nest blocks. Perhaps he couldn't think of any way of discouraging people from doing
> "I had the best books (Flanagan, Resig, Crockford)"
> Flanagan has been proven clueless
I think "clueless" is incorrect and inappropriate. He knows a lot as displayed many times in his book and I still find his book a useful starting resource for most browser-related issues. Yes his book has mistakes but that does not make him clueless.
>>> Moreover, the language Crockford defines isn't JavaScript, or even >>> javascript. It's a language where you aren't allowed to do
>>> ... { ... { ... } ... } ...
>>Where does he say that?
> In the syntax diagrams.
OK, I see what you mean. This is on the same page where he writes that "if(expression)" can only be followed by a block. The grammar he's defining here is not that of javascript, but of the subset he calls the Good Parts. That's the whole point of the book - dividing the language into good and bad (and, in the appendix, awful) parts. I think most people who work with any language for a while instinctively do the same thing in their minds, and Crockford wrote a book about it. As I said, it's not a tutorial, but a collection of opinions.
> I don't think he says in words that he doesn't want to nest blocks. > Perhaps he couldn't think of any way of discouraging people from doing
> ... { ... if (true) { ... } ... } ...
Off the top of my head I can't think of a single reason to use a block unless it's necessary (except following if/else/for/while/etc, which is a question of coding style) so I think that excluding them from the Good Parts was the correct choice. "if (true) {...}" doesn't make any sense at all. For the record, I do disagree on quite a number of other suggestions and opinions in the book, but that hardly made it worthless for me.
> > "I had the best books (Flanagan, Resig, Crockford)"
> > Flanagan has been proven clueless
> I think "clueless" is incorrect and inappropriate. He knows a lot as
His name has come up here a lot over the years. It seems to me that most of it was bad. I certainly wouldn't recommend buying his books. He's no Resig when it comes to cluelessness. I'll leave it at that.
> > > "I had the best books (Flanagan, Resig, Crockford)"
> > > Flanagan has been proven clueless
> > I think "clueless" is incorrect and inappropriate. He knows a lot as
> His name has come up here a lot over the years. It seems to me that > most of it was bad.
People seem to like to point out the mistakes because that is actually useful. It would be boring and pointless to read about all the he wrote that are correct.
> I certainly wouldn't recommend buying his books.
That is a different story. I would recommend his book but would warn that there are errors both small and large. I think a beginner is best served by a paper book that covers the language and the DOM. Flanagan's book fits that bill best of the options available. It isn't so good to say to a beginner, "hey there are some documents on there and there on the web. Try the terse specs and the Mozilla site and the archives of c.l.js are good but there is a lot of pedantic arguing to wade through. Just jump in the deep end with the sharks." Flangan's book is a much more gentle introduction.
On Oct 10, 9:07 pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com> wrote:
> [snip]
> A closure is a piece of code together with a binding of values to the > free variables of that code.
> A free variable is one that occur in the code, but is not declared > there.
So does it mean that even global variables in Javascript are `free variables' given the fact that they can be used without being declared or is it that the definition is a loose one?
Also, given the function:
---------------------------------->B-------------------------- function attachEvents() { var divs = document.getElementsByTagName("DIV"); if(!divs) return; for(var i = 0, maxI = divs.length; i < maxI; ++i) { var d = divs[i]; d.onclick = function() { // some complicated processing with a lot of variables alert("Hello from " + d.id); } }
Will the second invocation of the function `attachEvents' make the execution context of the first run along with the previously created function objects eligible for garbage collection or do they need to be explicitly grounded [set to null]?
sasuke <database...@gmail.com> writes: > On Oct 10, 9:07 pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com> > wrote:
>> [snip]
>> A closure is a piece of code together with a binding of values to the >> free variables of that code.
>> A free variable is one that occur in the code, but is not declared >> there.
> So does it mean that even global variables in Javascript are `free > variables' given the fact that they can be used without being declared > or is it that the definition is a loose one?
I variable is not inherently free or not. A variable occurence in a part of a program, e.g., function declaration, is free in that function if the function doesn't contain a declaration of that variable.
Example:
function foo(x) { return function(y) { alert(x+y); } }
This entire function has only one free variable: "alert". The variable occurences "x" and "y" are bound by the argument declarations of the surrounding functions.
The inner function: function(y) { alert(x+y); } has two free variables: "alert" and "x".
Notice that the same occurence of "x" can be both free and bound depending on the scope one consider.
> ---------------------------------->B-------------------------- > function attachEvents() { > var divs = document.getElementsByTagName("DIV"); > if(!divs) return; > for(var i = 0, maxI = divs.length; i < maxI; ++i) { > var d = divs[i]; > d.onclick = function() { > // some complicated processing with a lot of variables > alert("Hello from " + d.id); > } > } > } > window.onload = function() { > attachEvents(); > // something complicated > attachEvents(); > } > ---------------------------------->B--------------------------
> Will the second invocation of the function `attachEvents' make the > execution context of the first run along with the previously created > function objects eligible for garbage collection or do they need to be > explicitly grounded [set to null]?
That depends entirely on the javascript implementation.
Best case, nothing remains and the garbage collector claims it all.
Worst case, the garbage collector barfs on the DOM->JS function->DOM dependencies and collects nothing. That's a memory leak. I believe IE 6 might do just that.
> On Oct 10, 9:07 pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com> > wrote:
> > [snip]
> > A closure is a piece of code together with a binding of values to the > > free variables of that code.
> > A free variable is one that occur in the code, but is not declared > > there.
> So does it mean that even global variables in Javascript are `free > variables' given the fact that they can be used without being declared > or is it that the definition is a loose one?
The term "free variable" (as defined here) could be used to describe global variables that are referenced within functions. Regardless, global variables are not part of the binding described in the closure definition.
> Also, given the function:
> ---------------------------------->B-------------------------- > function attachEvents() { > var divs = document.getElementsByTagName("DIV");
Inefficient. Use the collection itself.
> if(!divs) return;
You don't need to do that with gEBTN.
> for(var i = 0, maxI = divs.length; i < maxI; ++i) {
Inefficient. Use a while that counts down to 0.
> var d = divs[i]; > d.onclick = function() { > // some complicated processing with a lot of variables > alert("Hello from " + d.id); > } > }}
You are leaking memory. Every one of these creates this chain:
[DOM element X] ---onclick---> [anon function] ---> [variable object] ---> [DOM element A]
You forgot to set divs to null too. Same issue.
Unfortunately, your design doesn't allow you to set d to null.
function attachEvents() { var el, index = document.getElementsByTagName('div').length; while (index--) { el = document.getElementsByTagName('div')[index]; el.onclick = (function(id) { return function() { alert('Hello from ' + id); }; })(el.id); } el = null;
}
Or better yet, attach one listener and use delegation.
[second attempt; the first didn't show up for some reason]
On 2008-10-13 20:56, David Mark wrote:
> On Oct 13, 1:14 pm, sasuke <database...@gmail.com> wrote: >> function attachEvents() { >> var divs = document.getElementsByTagName("DIV");
> Inefficient. Use the collection itself.
(see below)
>> for(var i = 0, maxI = divs.length; i < maxI; ++i) {
> Inefficient. Use a while that counts down to 0.
(That's micro-optimization, unlikely to produce any measurable performance gains. It also inverts the order of element processing, which may be significant in some cases.)
> function attachEvents() { > var el, index = document.getElementsByTagName('div').length; > while (index--) { > el = document.getElementsByTagName('div')[index];
Are you suggesting that calling getElementsByTagName() in a loop is more efficient than storing a reference to the collection in a variable, and using the variable in the loop? I doubt that, and some preliminary testing shows that your recommendation is consistently slower than sasuke's; in some implementations (Opera, Safari) even by a factor of 4.
> [second attempt; the first didn't show up for some reason]
> On 2008-10-13 20:56, David Mark wrote:
> > On Oct 13, 1:14 pm, sasuke <database...@gmail.com> wrote: > >> function attachEvents() { > >> var divs = document.getElementsByTagName("DIV");
> > Inefficient. Use the collection itself.
> (see below)
> >> for(var i = 0, maxI = divs.length; i < maxI; ++i) {
> > Inefficient. Use a while that counts down to 0.
> (That's micro-optimization, unlikely to produce any measurable > performance gains. It also inverts the order of element processing, > which may be significant in some cases.)
But not in this case.
> > function attachEvents() { > > var el, index = document.getElementsByTagName('div').length; > > while (index--) { > > el = document.getElementsByTagName('div')[index];
> Are you suggesting that calling getElementsByTagName() in a loop is more > efficient than storing a reference to the collection in a variable, and
Yes. Browsers optimize for that pattern.
> using the variable in the loop? I doubt that, and some preliminary
Doubt it all you want.
> testing shows that your recommendation is consistently slower than > sasuke's; in some implementations (Opera, Safari) even by a factor of 4.
Nonsense. Opera has a long article on their site about this.
> On Oct 14, 7:16 am, Conrad Lender <crlen...@yahoo.com> wrote:
> > [second attempt; the first didn't show up for some reason]
> > On 2008-10-13 20:56, David Mark wrote:
> > > On Oct 13, 1:14 pm, sasuke <database...@gmail.com> wrote: > > >> function attachEvents() { > > >> var divs = document.getElementsByTagName("DIV");
> > > Inefficient. Use the collection itself.
> > (see below)
> > >> for(var i = 0, maxI = divs.length; i < maxI; ++i) {
> > > Inefficient. Use a while that counts down to 0.
> > (That's micro-optimization, unlikely to produce any measurable > > performance gains. It also inverts the order of element processing, > > which may be significant in some cases.)
> But not in this case.
> > > function attachEvents() { > > > var el, index = document.getElementsByTagName('div').length; > > > while (index--) { > > > el = document.getElementsByTagName('div')[index];
> > Are you suggesting that calling getElementsByTagName() in a loop is more > > efficient than storing a reference to the collection in a variable, and
> Yes. Browsers optimize for that pattern.
> > using the variable in the loop? I doubt that, and some preliminary
> Doubt it all you want.
> > testing shows that your recommendation is consistently slower than > > sasuke's; in some implementations (Opera, Safari) even by a factor of 4.
> Nonsense. Opera has a long article on their site about this.
Trying to find that article, but nothing that exactly matches on the Opera site. Maybe I am thinking of something else. Regardless, the while loop is definitely faster in all implementations (no need to test that) and closures/memory leaks are the issue at hand.
As I mentioned, the best solution is to attach one listener and get the id from the event target. All of these other loopy patterns (closures or not) are silly.
David Mark <dmark.cins...@gmail.com> writes: > On Oct 14, 7:16 am, Conrad Lender <crlen...@yahoo.com> wrote: >> [second attempt; the first didn't show up for some reason]
>> On 2008-10-13 20:56, David Mark wrote: >> > function attachEvents() { >> > var el, index = document.getElementsByTagName('div').length; >> > while (index--) { >> > el = document.getElementsByTagName('div')[index];
>> Are you suggesting that calling getElementsByTagName() in a loop is more >> efficient than storing a reference to the collection in a variable, and
> Yes. Browsers optimize for that pattern.
Do you have any references for that? It sounds likely that they do something smart, but I find it unlikely that it will be faster to call a function to return the same value again than just looking it up in a local variable.
> Nonsense. Opera has a long article on their site about this.
> David Mark <dmark.cins...@gmail.com> writes: > > On Oct 14, 7:16 am, Conrad Lender <crlen...@yahoo.com> wrote: > >> [second attempt; the first didn't show up for some reason]
> >> On 2008-10-13 20:56, David Mark wrote: > >> > function attachEvents() { > >> > var el, index = document.getElementsByTagName('div').length; > >> > while (index--) { > >> > el = document.getElementsByTagName('div')[index];
> >> Are you suggesting that calling getElementsByTagName() in a loop is more > >> efficient than storing a reference to the collection in a variable, and
> > Yes. Browsers optimize for that pattern.
> Do you have any references for that? It sounds likely that they do
I have been trying to dig it up myself.
> something smart, but I find it unlikely that it will be faster
Thanks for that, but it is possible that I did something dumb in this case. The fact that I can't find the article is not encouraging.
> to call a function to return the same value again than just looking > it up in a local variable.
Well, define looking it up in a local variable when the local variable is a reference to a live nodelist? I can't as I don't write browsers.
> > Nonsense. Opera has a long article on their site about this.
>> > function attachEvents() { >> > var el, index = document.getElementsByTagName('div').length; >> > while (index--) { >> > el = document.getElementsByTagName('div')[index];
>> Are you suggesting that calling getElementsByTagName() in a loop is more >> efficient than storing a reference to the collection in a variable, and
> Yes. Browsers optimize for that pattern.
I would also like to see a source for that.
>> using the variable in the loop? I doubt that, and some preliminary
> Doubt it all you want.
>> testing shows that your recommendation is consistently slower than >> sasuke's; in some implementations (Opera, Safari) even by a factor of 4.
> Nonsense. Opera has a long article on their site about this.
Well. Here I am, having tested this in 5 current browsers (not comprehensive, yes, but as I said, they were preliminary tests), and here you are saying "nonsense". Is that all you've got?
> >> > function attachEvents() { > >> > var el, index = document.getElementsByTagName('div').length; > >> > while (index--) { > >> > el = document.getElementsByTagName('div')[index];
> >> Are you suggesting that calling getElementsByTagName() in a loop is more > >> efficient than storing a reference to the collection in a variable, and
> > Yes. Browsers optimize for that pattern.
> I would also like to see a source for that.
> >> using the variable in the loop? I doubt that, and some preliminary
> > Doubt it all you want.
> >> testing shows that your recommendation is consistently slower than > >> sasuke's; in some implementations (Opera, Safari) even by a factor of 4.
> > Nonsense. Opera has a long article on their site about this.
> Well. Here I am, having tested this in 5 current browsers (not
Yes, there you are. Your testing has been previously proven suspect. Pardon me if I am non-responsive.
> A big Thank You to PointedEars and Jorge for helping me get closer to > the truth.
Seems the article hasn't been updated since you started this thread, are you going to?
Don't be discouraged by criticism, teaching something is a very good way to learn it thoroughly if you are prepared to learn yourself from the experience.
A couple of tips, some mentioned by others, some not:
1. Closures are a feature of ECMAScript. Javascript is not a subset of ECMAScript, quite the opposite, so I'd remove the note below the title. Crockford’s book is just his opinion on some features of the language that he considers good/bad/ugly, I don’t think it’s a serious attempt to modify the standard (although I haven’t read it).
2. The article’s definition of a closure is meaningless to me, but then again, I haven’t read a one-line description that makes sense. To me a closure is the ability to keep a reference to a function variable after the function has finished executing. That isn’t particularly accurate from a technical viewpoint, but it does the job for me.
3. In the “Why do you want closures” section, the statement “...the closure is invisible except to the singe public function of the closure” is misleading: any number of functions can have closures to the variables of a function. Also, if the functions that have those references are public, they can be called privileged (see Crockford’s article on public and private members in javascript[1]). A reference to that article should be included.
4. A closure is a consequence of declaring one function inside another using either a formal declaration, function expression or statement. It’s only useful if some reference is kept of course, but the closure isn’t the variable reference, it’s the ability of the “inner” function to access the activation object of the outer function and its variables.
I think you should reference the FAQ article[2] which is not only a comprehensive and technically excellent article on closures, it teaches an awful lot about the fundamentals of functions in general.