Thursday, May 26, 2011
Then say this website needs to add another, separate progressive-enhancement script. Or two. Or more. As long as you had only one script, you could just have the script set window.onload to its main function and be done with it, but as soon as you have multiple scripts this breaks.
Enter function chaining. If each of these scripts chains onto the end of the existing window.onload function, you can stack them ad infinitum, or at least to the practical limits of memory and computational power. A first attempt to apply this to the above example might look something like this:
Unfortunately, this has a few problems: First, it uses a global variable to store the old onload function, so if another script happens to use the same variable name, the value will get clobbered. Here is similar example but using the onclick event for ease of illustration - try running this in the FireBug console and then clicking on the document to see for yourself:
Second, although the original function is invoked, it does not have any of the expected arguments passed to it (for example, the event argument) as seen in this console example:
And third, the value of “this” is not consistent as can bee seen with this example:
So how do you resolve all of these issues? Lambda expressions, the “arguments” variable, and the “apply” method, of course! If this terse and snarky answer doesn’t immediately answer your questions, read on for more details…
For the argument passing issue, we could manually pass some fixed number of arguments to the chained function, but a more elegant solution would work with any number of arguments without knowing in advance how many will arrive. The “arguments” array is present inside any function and contains the complete set of arguments in the form of an array. But since this is an array, if you just pass it in a normal function call, it will be sent as a single array object, not as the multiple individual arguments it once was.
This issue and the final problem with “this” are both solved by the “apply” method. This is a method available on all function objects (remember, everything is an object, even functions!). By using this method to invoke the function rather than the usual idiom, a value for “this” can be specified and an array object can be exploded into individual arguments.