views:

80

answers:

3

(I'm using prototype.js here, but I imagine the same holds true across other libraries as well)

I often find myself writing code like this:

var search_box;

Event.observe(window, 'load', function() {
    search_box = $('search_box');
});

function doSomething(msg) {
    search_box.innerHTML = msg;
}

Rather then writing it simply like this:

function doSomething(msg) {
   $('search_box').innerHTML = msg;
}

My intention is to avoid having to traverse the entire DOM searching for the "search_box" element everything I need access to it. So I search for it once on page load and then stick the reference in a global variable. However, I don't recall ever seeing anyone else do this? Am I needlessly making my code more complex?

+1  A: 

I usually do the same thing, the reason you don't see it often is probably because you don't see well written code often that's optimized ( nevermind the whole preoptimization is evil thing ) - I say if you can optimize it without headaches then why not?

Realistically speaking though that's a very very trivial DOM lookup, you should only begin to worry if you're iterating through dozens of elements and being vague in the selectors.. so I wouldn't worry too much about it unless you can really notice certain parts of your web page loading rather slowly, in which case you should store the multiple elements you access in the outer scope's variable.

Good:

(function() {

var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.

function foo() {
   els.something();
}

els.somethingElse();

})();

Bad:

(function() {

var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.

function foo() {
$$('.foo span').something();
}

$$('.foo span').somethingElse();

})();
meder
I agree with your example, but only because the "bad" one has duplication of the CSS selectors. In my book, duplication is a worse offence than failing to do premature optimisation. :-)
molf
+1 for scoping the variables in their own context (is closure the right word here?)
Erik van Brakel
afaik you can't specify a context to $$, but you can do something like: $('elementId').select('.foo span')
PatrikAkerstrand
+3  A: 

This is called premature optimization.

You are introducing a global variable to optimize something you have not profiled.

Your assumption that the $ "traverses the DOM" is incorrect. This function is implemented using document.getElementById which is the fastest way to access an element in the DOM.

I suggest coding your javascript using basic programming best practices such as avoiding global variables, and not optimizing without profiling. Once your application is working as expected, then you should profile it (using firebug) and address the area(s) where it is slow.

hobodave
"You are introducing a global variable" - well we haven't seen his entire script so he could be doing this within a private namespace. I would disagree because assuming he's declaring the variable not globally, there's virtually nothing complex, there's barely any extra work to optimize this. One may argue that you can even save time by relying on the variable, since you dont have to specify quotes for Prototype, no need to type the `'`s and the `$`.If you can optimize while efficiently coding, then why not?
meder
"If you can optimize while efficiently coding, then why not?" - Answer: the so called "optimisation" may have introduced a bug in the code. What if `doSomething()` is called before the window's `onload` event fired? I'm not saying it can (I don't know the actual project), but it should be obvious that the code has become more complex and prone to errors.
molf
@meder: I can neither prove nor disprove whether the given code is within a global context. What I can do, however, is answer based on the provided information. Given the provided code, the variable is global. Thus, my answer requires that no assumption be made. Regarding the argument that not having to type dollars and apostrophes is a time saver worth increasing code complexity; the programmer who presents this argument to me is the programmer not hired.
hobodave
@molf: precisely
hobodave
Thanks for your comment. It caused me to think a bit more critically about my question. However my testing indicates that you are incorrect. See my answer below.
jamieb
@jamieb: It should be common sense that a variable access is faster than a function call. That doesn't make my answer "incorrect". You're still introducing a global variable, and this is still a ridiculous micro-optimization.
hobodave
A: 

I decided to spend a bit of time doing some testing to get some hard data. The answer is that preloading the elements into global variables is twice as efficient as accessing them using the DOM getElementById method. (At least under FF 3.6).

Subsequent accesses to the objects is also more efficient using the global variable method, but only marginally so.

jamieb