by Angus Croll

JavaScript and Russian Dolls

In JavaScript, functions are variables which means they can be created and replaced at run time. Thanks to the pioneering efforts of Richard Cornford (Russian Doll Pattern, 2004), Peter Michaux (Lazy Function Definition pattern, 2007) Oliver Steele (One-Line Memoization, 2006) there are nifty techniques that exploit this capability.

First, a very simple example to illustrate the principle:-

var pushTheRedButton = function() {
//reassign a new function to the variable pushTheRedButton
pushTheRedButton = function() {
//this line gets called on all subsequent visits</span>
alert("Now look what you've done!");
}
//this line only gets called on the first visit</span>
alert("Don't ever push this button again!");
}
pushTheRedButton(); //"Don't ever push this button again!"
pushTheRedButton(); //"Now look what you've done!"

I’ve conjured up a bunch of real life examples and organized them into three pattern types

1. Temporal – Functions that get modified based on passage of time or number of iterations.

Consider an application that calls a lengthy process when asked to shutdown. Sometimes the user will get impatient or uncertain and hit the button again before shutdown is complete. We could disable the button, but that’s not necessarily re-assuring to the user who doesn’t know what’s going on. Instead we can do this :-

This works great for shutdown because when the app is re-started the default shutdown function gets reloaded. But what if the lengthy process is a non-terminal one, such as a download? Subsequent downloads would simply display the “still downloading” message, which is wrong. We can fix this by defining the default download function in the object prototype and redefining the modified function at the instance level where it can be deleted by a callback when the download is finished:-

Sometimes subsequent iterations of a function require more subtle modifications. The following is a URL object, designed to take components in object form and return the complete URL string on request. One problem is the queryParams portion of the string – the prefix for the first param pair needs to be a ‘?’ but for subsequent parameters pairs it must be a ‘&’. The entire URL object is quite long but I wanted to include it so others can run it. I’ve highlighted the lines where I’ve applied the function replacement pattern (note: this example uses the curry function which I introduced in a previous post):-

I’ll be the first to admit this is probably overkill. It would be perfectly fine to employ a ternary on the iteration index instead. However I think the use-case it illustrates is of value, and the solution offered may be of use to readers encountering similar problems. Let me know if you come up with a better example.

2. Conditional – functions discard conditional logic that will never apply to them

The inner text of a DOM element can be retrieved in one of two ways according to browser type.

This eliminates the need for condition checking every time the function is called. The return statement on the last line will only be invoked on the first pass.

In the above examples the savings are relatively small because the conditional test has a tiny footprint. But such tests are often expensive and multipart (if..else…else…else). Moreover, variables (including potentially bulky anonymous functions) declared in the original function are freed up for garbage collecting providing you’re careful not to reference them in the replacement function. Finally, removing unnecessary logic at runtime can improve the debugging experience.

Here is a Person object which includes a method to return the Person’s zodiac sign. This calculation is non trivial (ok, pretend it is please) so after the first pass we define a new method at the instance level which simply returns the result which we’ve locked into the function by closure.

By the way please go easy on my zodiacLookup object, yes it takes no account of timezone or place of birth. Those millisecond calcs were tricky enough as it was ;-)

Post navigation

17 thoughts on “JavaScript and Russian Dolls”

I will often rewrite functions inside themselves to prevent things that should only run once from being called again, mainly in terms of page scripts. I’ll have a minified/merged script that includes functions for each template, and page throughout the site…

In doing this I can create a cohesive web application, where the only output from the page is one script include, and one script tag with page options, localizations and a call to the pageNameLoad method. This does have a larger initial load time, than separate scripts, but means everything in script is pretty much loaded one time, and cached, and subsequent pages in the site/app load more quickly.

@jpvincent – thanks for the input. Yes that would work too – the downside is you have to invoke a conditional each time (and you need an extra variable)…aside from the minor performance hit, it makes debugging a bit clunkier IMO. Compare to Russian Doll pattern where you get to de-reference your unnecessary junk after the first pass

These are very entertaining and enlightening and I tend to make really heavy use of Javascript’s promiscuous polymorphism but I’d have to say that I’d not allow any of these examples in a code base I was in charge of.

The issue is that it introduces state in a weird place where you don’t expect it. The code with just boolean variables might be a littel longer and a little less elegant, but it’s easier to understand and debug – and also you don’t get issues like seeing “loading” still if your load is interrupted, because you simply create a new instance of your class each time.

Asen, thanks for pointing this out (actually I just mentioned instanceof problem in my prototype post). In general I find JavaScript constructors do not respond well to functional applications – for example currying and composition will also create new functions which disrupts the prototype chain. This speaks to the fragile nature of Constructor prototype dependency.

* There missing semicolons after many assignments.
* The textContent function has a mistake of checking myDiv.innerText in boolean context. The problem is that when myDiv.innerText is empty string, “”, it evaluates to false.

– when getMyText is called where myDiv.innerText == “”, it will get the function that returns myDiv.textContent. The problem with that is that for IE <= 8, if that happens the first time, then subsequent calls to that method name will always return undefined (because IE <= 8 does not have textContent).

I’m using JS both for web development and desktop application testing (via TestComplete). These both involve capability sniffing and expensive initial setup operations. Up till now I had used globals then moved onto closures to achieve this. Now I am dolling up my scripts.

I have read the Crockford and Zakas books this year but to me this is the Chuck Norris of all JS techniques and I commend you, sir.

This is an interesting principal, but I just want to make sure that other understand that the original function will still exist if you referenced with another variable. The following is a modified form of the first example which illustrates that the original function still exists:
var pushTheRedButton = function() {
//reassign a new function to the variable pushTheRedButton
pushTheRedButton = function() {
//this line gets called on all subsequent visits
alert("Now look what you've done!");
}
//this line only gets called on the first visit
alert("Don't ever push this button again!");
}, originalFn = pushTheRedButton;