What's even more hilarious is the code in his "My Library".
I'm far too much of a generalist to consider myself a JavaScript expert. However, even I can pick out a number of items in his lib that shouldn't have been handled the way they are:
- He declares $ in a global context without first checking for its existence;
- He uses RegExp objects constantly -- in 50 different places in his full "mylib.js" -- including in cases where a simple indexOf would be better, and, best yet, he doesn't bother to cache them in any of the dozen or so cases that I examined. Wasn't that one of his criticisms of someone else's code?
- His treatment of camelCase is truly embarrassing, relying on an ugly RegExp every time it's called. Try something like this instead:
There, now you only need to camelCase the property for anything once. JavaScript's object handling makes caching this kind of stuff soooo easy. And, if you do have to have a camelCasing function, try to do it with as little overhead as possible -- use the tools that JavaScript gives you, instead of capturing the string parts in a match and then .join()ing them and all that other nonsense.
His library doesn't demonstrate any of the kind of specialized language knowledge that he accuses other library developers of lacking, and it has at least some of the same weaknesses that he criticizes others' works for.
There's a tradeoff between download time and execution speed there, and download time usually wins. I wrote the camelCaser in Google Websearch (basing it off Closure), and I used a simple regexp without memoization. You can burn a lot of cycles in the time it takes to download a hundred bytes over 56.6k, and often a camelCaser is used in situations like an animation loop where speed doesn't matter as long as you come in under the frame rate.
- minifying and gzipping the javascript files is considered standard practice now, and the code I posted as-is is actually shorter than David Marks' case [* I lied! It's not, by 100 chars. Even shortening the object references kept it a bit longer. I don't think this defeats the rest of my points though.]. It could further be shortened, a lot -- to the point that for all practical purposes it's as small as a non-memoizing version.
- I tend to use a camelCaser in much more than simple animation loops -- any time for example that the style attributes for any element are referenced. i.e., it qualifies as an inner-most function.
- Although it's true that in animation loops you just have to beat the frame rate, let's keep in mind that there are a wide variety of processors and systems in use, and not everyone is using the latest dual-core Intel system with 3 gigs of RAM.
As a point of personal style, I much prefer to take the shortest, fastest, least-resource-intensive path for any given task, even if it's not strictly necessary to do so. As an end-user, I'm disgusted beyond description with the mindset that has become so prevalent among programmers, where efficiency is something that should be solved in hardware. It's absolutely frustrating that there are sites where the programmers have made so many concessions to speed in the name of rapid development that I can't even get the site to load in a few seconds on a 1.5 ghz G4.
So, yes, you're right, but I think the bit from David Marks' code is still naive and still does not make best use of the language:
camelize = function(name) {
var m = name.match(reCamel);
return (m)?([m[1], m[2].toUpperCase(), m[3]].join('')):name;
};
You had a good point about total size of the code being downloaded, so I went back and tried to see if I could shrink mine a bit without pulling any dirty tricks -- when I realized that a chunk of his code is 'hidden' in the reference to the regular expression object he's created elsewhere.
With that added, and matching my code style to his, my version is less than 20 characters longer than his -- and that's without doing anything sneaky.
But, maybe there just isn't a big difference in speed? So, I set up a quick test. Again, I wanted to be fair, so I could understand what was going on. The two tests are identical, I didn't advantage mine in any way or disadvantage his.
The results?
Given a list of 11 valid CSS properties to "camelize", some with dashes and some without, my code can camelize the set 20 times over in 1 to 2 milliseconds.
The non-memoizing version can camelize the set 20 times over in ... 1034 to 1212 milliseconds.
That's a significant difference, IMO.
Tested on Firefox 3.5/Mac.
...all that said, thanks for reminding me about function size and download speed. I try to keep my own library at under 1000 source lines of code, but there are definitely some areas where I can sacrifice a few lines to lose a chunk of text. (Like, wrapping "typeof object != 'undefined'" into an "undef(object)" function.)
You missed the point. Well, several points. My Library was written years ago and the idea was to support "ancient" browsers like Safari 2 as well as all future browsers. As the fairly torturous test page still works in IE8 (all modes), Safari 4 and Chrome it would seem a rousing success. In the meantime, jQuery has been virtually rewritten to get rid of the browser sniffing. Guess where they got the ideas (and figure they botched their implementation).
Yes, memorizing camelized styles would be more efficient, but then the library doesn't deal with hyphenated ones in the first place. It's used in exactly two places and neither has anything to do with styles. Instead, it deals with (very rarely encountered) hyphenated _attributes_ (you should have guessed, or God forbid read the code you were criticizing).
And aren't you just picking one (tiny) bit that you can sort of relate to and mouthing off without any real clue about what you are talking about? <whine>And why didn't _you_ report it to the author to be constructive, build a community, etc. What an awful jerk!</whine>
BTW, your version will blow up in Safari 2 due to the function passed to replace. Good luck with that!
Hi, welcome to HN! I sincerely hope that you will bring a different tone here than you do on comp.lang.javascript.
People tend to measure the "success" of their libraries or other code based upon whether or not it accomplishes their goals. If your goal was to simply build a set of abstractions, continue support for ancient browsers, and ensure that it continues to work for future browsers, then you've accomplished it and that's great.
However, you fail then to recognize the goals of other frameworks and libraries which differ from your own. That is, they sacrifice compatibility with very old browsers for the sake of improved performance and support for newer browsers; or they sacrifice strict correctness for improved rates of development; or they sacrifice other aspects of Javascript-specific techniques for the sake of readability or establishing patterns familiar to novice programmers.
The authors of other frameworks can no more be criticized by you for failing to meet your goals, than we could criticize your library for failing to meet our goals.
Indeed, you're correct that I did not read every one of your more than 9,000 lines of code (almost 330K!) for the complete library. Rather, given your penchant for reading a few lines of some framework, critiquing them, and then declaring them to be no longer worth your time -- I thought I'd try the same.
...Actually, I'm being needlessly rude there. The truth is, I did attempt to review portions of code inasmuch as I had time for. Much of it was simply not notable; I picked out the camelization for one point because I had been tuning my own just a few nights ago.
Thanks (seriously) for pointing out the Safari 2 incompatibility. I'll consider whether adding support for Safari 2 is worth re-working that line. (Probably not, but maybe.)
We could continue to dicker back and forth on the relative merits of one bit of JavaScript versus another, but I'd rather keep working on mine, other people would rather start writing their own obvious unit tests, and you would hopefully rather update your library or something.
You don't get it. See the examples I posted recently in CLJ (at the end of that jQuery thread, for example). It does anything you can imagine, including a jQuery-like interface if you really like bad interfaces. :) Or you can write your own OO interface.
jQuery is _downstream_ from My Library. If you go back a couple of years in CLJ, you'll find that I'm the one who tirelessly argued with Resig and co. until they dumped UA sniffing. And yeah, they copy code and ideas from me to this day. But that is _not_ why I point out the botched implementations of those (and other) ideas. I point them out because the code is bullshit.
All of that stuff about improved development time and readability and support for whatever browsers misses the mark (no pun intended) as well.
* The others are not more readable
* The others are not more advanced (despite my Write Once, Do Nothing strategy).
* The others are not more compatible (not even close)
* The others do not perform better
* The others do not have better support (the authors are too confused about what they are writing or copying)
The only thing the others have going for them is that they actually (disingenuously) market their projects. I don't have the time or need to do so.
The library is only 330K if you select _everything_ in the builder, which is the equivalent of jQuery + 100 plug-ins. It's got easily the best Flash module, a unique audio module, "sidebar" widgets, a CSS selector query engine, animations (including DirectX), etc., etc. And it all works going back a decade or so and continues to work going forward (I rarely touch it). And contrary to the laughable comment I saw in here, it perfectly suitable for use in the "Real World". That expression is so tired (and meaningless usually) it is in a coma. I sometimes wonder if the people who write things like "Real World" and "snark" actually talk like that. :)
I don't know what you mean by "simply not notable". On technical, usability and compatibility merits, it's the most notable blob of cross-browser JS ever published. But I never really called attention to it other than as a way for others (e.g. Resig) to learn. When it came out, all of the frameworks were doing crap like this:-
if (isIE6) {
} else if (isSafari || isIE8)
}
...and about to collapse under the weight of all of these flaky forks. You can't maintain BS like that.
Read your history, you will get an extreme sense of Deja Vu (and perhaps a laugh or two).
And I never said anything about Resig co-opting my "obvious unit tests". There's a lot more than tests on that page. Nor do I have to update My Library (that's the main point of feature testing).
Seriously, you just might learn something. This is why I speak loudly (and carry a big script). :) Otherwise, all of you "hackers" might have remained oblivious to the fact that jQuery, Prototype, MooTools, etc. are Z-grade scripts at best. It's not always a poor use of the language, but more often a poor grasp of cross-browser scripting techniques, which leads to endless Beta tests, wholesale substitutions, etc. It's a relatively hard way to go, despite what the commercials (blog posts) tell you. ;)
I'm far too much of a generalist to consider myself a JavaScript expert. However, even I can pick out a number of items in his lib that shouldn't have been handled the way they are:
- He declares $ in a global context without first checking for its existence;
- He uses RegExp objects constantly -- in 50 different places in his full "mylib.js" -- including in cases where a simple indexOf would be better, and, best yet, he doesn't bother to cache them in any of the dozen or so cases that I examined. Wasn't that one of his criticisms of someone else's code?
- His treatment of camelCase is truly embarrassing, relying on an ugly RegExp every time it's called. Try something like this instead:
There, now you only need to camelCase the property for anything once. JavaScript's object handling makes caching this kind of stuff soooo easy. And, if you do have to have a camelCasing function, try to do it with as little overhead as possible -- use the tools that JavaScript gives you, instead of capturing the string parts in a match and then .join()ing them and all that other nonsense.His library doesn't demonstrate any of the kind of specialized language knowledge that he accuses other library developers of lacking, and it has at least some of the same weaknesses that he criticizes others' works for.