Wednesday, August 15th, 2007
Lazy Function Definition Pattern
Peter Michaux has written about the Lazy Function Definition Pattern.
His article takes you down the path of implementing a simple problem:
Write a function foo that returns a Date object that holds the time that foo was first called.
After critiquing 3 iterations he ends up with:
-
-
var foo = function() {
-
var t = new Date();
-
foo = function() {
-
return t;
-
};
-
return foo();
-
};
-
He then uses the technique to implement getScrollX, and to talk about how you can use defineGetter in certain browsers to simulate lazy definition for properties that aren’t functions.












This function has changed my life
I dont get it, is this being sarcastic?
nice try, but don’t rely on it too much, or you’ll get memory leaks via closures
Why not use this?
var foo = function() {
var t = new Date();
return function() {
return t;
};
}();
Ugh. Had to read the article for this to make any sense at all.
Brilliant!
Whether or not I’ll ever use it…. tough to say
Oh, I made a mistake. My foo() only returns the Date object which is generated when the foo() is defined.
Not for nothing, but…
var foo=(function(){ return new Date(); })();
…executes the function once, no closures are involved, and the function itself falls out of scope after executed. Conditionals inside are more than fine. We use this all over Dojo (particularly in 0.9) for some of the exact reasons described, but we don’t create any unnecessary functions (though we probably do need to iterate over the codebase once we finally release 0.9 and make sure of that.)
btw, a better example for Ajaxian to post would have been the page scroll example; it clearly shows the reasoning behind such a technique. The example given above is not a good one, all it does is demonstrate using and creating functions on the fly.
Still, wrapping the entire thing in a function that is defined and executed once is probably the most efficient way of doing it. Taking a cue from one of the comments in the article:
var getScrollY=(function(){
if(window.pageYOffset) return function(){ return window.pageYOffset; };
if(document.documentElement.scrollTop) return function(){ return document.documentElement.scrollTop; };
if(document.body.scrollTop) return function(){ return document.body.scrollTop };
return function(){ return -1; }
})();
Once the outer function is executed, it falls out of scope and only the conditional met remains.
Hi Tom, In your first post your foo will hold a Date object for when foo was initially defined. The goal of the example in my article is to define a foo() that will return a Date object that corresponds to the first time foo() is _called_. In your second post the third conditional will not work because document.body does not exist when the script is loaded in the head element of the document. I discuss this in the article and this lack of information when a function is defined is the impetus for lazy definition altogether.
Thats awesome, I never knew you could redefine a function within itself.
@anonymous: Closures do NOT cause memory leaks. Closures are a core part of JS, almost as foundational as mutable variables, and are integral to good JS programming. Every JS engine handles them with leaking. Memory leaks were caused in IE by circular references that included DOM elements, and these circular references were easily created with closures, but it wasn’t the fault of closures.
Function replacement is also used by AOP/function interposing style event handling, which I believe is the mechanism that Dojo uses for it’s connect function, and really love this style of event handling. A brilliant demonstration of the power of JS.
Peter, great job demonstrating another use of this power of the dynamic nature of JS.
@Peter: I’d suggest then that you make it a little clearer what your goal is–for instance, stating exactly what you said to me in that paragraph called “Warm up problem”. Too many people miss the distinction, particularly when it’s posted on Ajaxian first.
Also, you’re correct WRT document.body. It’s a bad sniff and the only reason I used it here was to illustrate the point, using an example someone posted as a comment to your post. Although IIRC, that branch would never be reached (since IE, which IIRC is the target of that sniff) will respond to the branch before it.
IMHO, WRT to the example, it’s the variable redefinition inside the body of the function itself that is questionable. But understandable.
Is there a reason why you don’t want to define something at load time (aside from waiting for a document to finish loading, at which point you could execute this onload)?
Tom,
IE will respond to document.documentElement or document.body branches depending on which mode it is in. Richard Cornford’s article that I reference explains in detail
http://www.jibbering.com/faq/faq_notes/not_browser_detect.html#bdScroll
If defining getScrollX/Y functions are delayed to window.onload then the user may interact with the page before the scroll functions are defined. Having them self-define on demand is a real advantage.
Peter,
This is useful information. I’m glad you’ve shared and explained it.
It’s particularly useful for object detection where you need to define functions for a particular browser. So, rather than check for say — document.attachEvent or document.addEventListener each time the addEvent method is called — you could just do it once and define the function.
Oliver
Very nice.
And, Peter, I can’t see how you could explain your goal better than you did.
@Peter:
Granted (WRT the particular example), but again I think you’re picking a tree from the forest. I used that as an example because someone posted it as a comment on your site. It’s not an approach I would take for determining scroll position but everyone has different ways of doing things, and most of them are good solutions.
WRT to clarity, I learned the hard way that even graduate students benefit from points that are crystal clear. Even a small addition like “as opposed to defining this when the code is loaded” would be a benefit. I had no less than 3 pretty smart people take a look at this post (at Ajaxian) and then ask me “what’s the point of what he’s doing?”, even after reading your post. And obviously I missed part of your point as well (though admittedly I did not read it slowly enough).
The point I was trying to make in my second comment had nothing to do with scroll position and everything to do with pure JS; redefining a variable like that in something you’re executing has the potential for all sorts of side-effects, and while it’s a neat demonstration of some of the things JS is capable of, I would consider that to be a dangerous path to go down. You obviously use it correctly but like so many other things you can pull with it, it has an enormous potential for misuse and abuse–as is so often seen on the Web.
It reminds me of an article I read a while ago (think it was on Sitepoint but I’m not remembering off the top of my head) where someone was trying to demonstrate how to do “real OOP” through returning a function definition as the result of the new constructor. It works, and it demonstrates some of the real flexibility of the language (which is one of the reasons I love it) but it also demonstrates something that has a serious potential for abuse. We in the JS community have been seriously lax WRT to making it clear when and why we do tricky things, and that has a lot to do with the commentary I’ve been making.
Wouldn’t the following be slightly more efficient?
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return t;
};
In this way, the first time you call it, you wouldn’t need to call the redefined foo() again just to get the value of t?
That risks too much confusion just to save an if. I think this is better:
var foo = function () {
var t;
return function () {
return t || (t = new Date());
};
}();
My second observation is regarding the naming of the pattern in this article. I find it to be not lazy at all. In fact, what it suggests to do is always upfront instead of delaying, therefore it is the opposite of lazy.
Are you kidding? That’s an attempt to reduce confusion? If your goal is to reduce confusion, why redefine the method you’re inside of?
Douglas’ solution seems the most intuitive to me. I don’t like having the function’s name inside the function body, although you could do what another commenter did and use arguments.callee.
Regardless, this seems like a useful idiom. If you don’t like it or are confused by it, don’t use it.
Here’s a way to use it in real life:
function makeLazyDef(decideWhichFun) {
var f;
return function() {
if (f) {
return f();
}
f = decideWhichFun();
return f();
};
}
var test2 = makeLazyDef(function() {
var t = new Date();
// expensive if statements are here
alert('fun creation');
return function() {
return t;
}
});
var test3 = test2;
var test4 = makeLazyDef(function() {
alert('deciding what to use...');
if (typeof window.pageYOffset == 'number') {
return function() {
return window.pageYOffset;
};
} else if ((typeof document.compatMode == 'string') &&
(document.compatMode.indexOf('CSS') >= 0) &&
(document.documentElement) &&
(typeof document.documentElement.scrollTop == 'number')) {
return function() {
return document.documentElement.scrollTop;
};
} else if ((document.body) &&
(typeof document.body.scrollTop == 'number')) {
return function() {
return document.body.scrollTop;
}
} else {
return function() {
return NaN;
};
}
});
var test5 = test4;
Kevin, the term “lazy” comes to us from the real world, where this pattern has been in widespread use for decades and is called “lazy caching”.
Rethinking, the only problem with your solution is that we would be filling the memory with variables that would never be released, just because of the closures.
*1# Case*
Suppose “foo” should return a static value, result of an intensive and complex code.
Using the proposed pattern, we would have something like this:
var foo = function() {
var result ;
var a,b,c,d,e ;
// using a,b,c,d,e to fill return
foo = function() {
return result;
};
return foo();
};
In the above example, “a,b,c,d,e” will never get released just because of our closure, even if not anymore needed. We just need “result”.
I was tempted to mix your solution with Jona’s proposal, which seams to bring better results regarding memory usage:
var foo = function()
{
return arguments.callee.t || (arguments.callee.t = (function(){
var result ;
var a,b,c,d,e ;
// using a,b,c,d,e to fill return
return result ;
})());
};
But, in the above example, the calculation will run for all calls if the final “result” is null, false, 0, NaN, etc. So, this is not the definitive way to go.
After further thoughts, I’ve also considered that, the “return a || b” approach, internally, has the same value (and possibly the same performance) as “return a ? a : b”, because in both cases the compiler will have to check the value of “a” before returning it (it means that it is not true that “a” is “immediately” returned in the first case). So, this is not a real shortcut.
So, theoretically, the following could be a definitive solution for this case:
var foo = function()
{
if ( typeof arguments.callee.t != 'undefined' )
return arguments.callee.t ;
var result ;
var a,b,c,d,e ;
// using a,b,c,d,e to fill return
return ( arguments.callee.t = result ) ;
};
Which means that we are back to the “Ancient Technology”, not opting to use the confusing “Module Pattern”, considering that “Functions are Objects”, but considering also that arguments.callee.t could be any kind of “defined” valued.
*2# Case*
Supposing instead the “foo” should return a value that uses different algorithms, chosen after a complex calculation.
Here we have the getScrollY example again, which will have the same memory allocation issue explained in the previous case.
Just to exemplify, suppose we code in the following way:
var getScrollY = function() {
if (typeof window.pageYOffset == 'number') {
return (getScrollY = function() {
return window.pageYOffset;
})();
}
var compatMode = document.compatMode;
var documentElement = document.documentElement;
if ((typeof compatMode == 'string') &&
(compatMode.indexOf('CSS') >= 0) &&
(documentElement) &&
(typeof documentElement.scrollTop == 'number')) {
return (getScrollY = function() {
return documentElement.scrollTop;
})();
}
var body = document.body ;
if ((body) &&
(typeof body.scrollTop == 'number')) {
return (getScrollY = function() {
return body.scrollTop;
})();
}
return (getScrollY = function() {
return NaN;
})();
};
In the above case, we have a complete chaos, because “compatMode”, “documentElement” and “body” will be part of the closure scope forever, even if not needed in all cases (and potentially leaking).
In this case, a sane proposal, achieving the performance enhancements aimed by your pattern, would be using an old way of avoiding closures, by defining all functions outside “foo”:
var getScrollY = function() {
if (typeof window.pageYOffset == 'number')
return (getScrollY = getScrollY.case1)();
var compatMode = document.compatMode;
var documentElement = document.documentElement;
if ((typeof compatMode == 'string') &&
(compatMode.indexOf('CSS') >= 0) &&
(documentElement) &&
(typeof documentElement.scrollTop == 'number'))
return (getScrollY = getScrollY.case2)();
var body = document.body ;
if ((body) &&
(typeof body.scrollTop == 'number'))
return (getScrollY = getScrollY.case3)();
return (getScrollY = getScrollY.case4)();
};
getScrollY.case1 = function() {
return window.pageYOffset;
};
getScrollY.case2 = function() {
return documentElement.scrollTop;
};
getScrollY.case3 = function() {
return body.scrollTop;
};
getScrollY.case4 = function() {
return NaN;
};
Here again, we have complete freedom in the getScrollY main calculations, avoiding closures. By using the “Functions are Objects” approach, just one of the “case1″, “case2″, “case3″ and “case4″ references will remain after the first call to getScrollY, freeing unneeded memory allocation too.
Conclusion
—-
Your pattern is interesting, but must be very well controlled while coding it. The above two cases are examples where it would work, but would not perform well regarding memory management (essentially because of the closures), and the proposed patterns could give better results, achieving similar performance enhancements.
Ps.: I’ve written all the code in this textarea… so, please don’t give much attention to possible typos.
@Tom
You’re probably right but your example uses a “one-time function” while, in my opinion, if You don’t need a closure it’s quite a non-sense.
var u,getScrollY=
window.pageYOffset!==u?function(){return window.pageYOffset}:
document.documentElement.scrollTop!==u?function(){return document.documentElement.scrollTop}:
document.body.scrollTop!==u?function(){return document.body.scrollTop}:
function(){return -1};
same result, any extra function creation or execution.
I suppose if You’re looking for performances the best way is to assign directly correct function (depending on browser) and not switching browser on every function call:
var doStuff = function(){if(IE)doIEStuff();else doFFStuff();};
// a better way (performances)
var doStuff = IE ? doIEStuf : doFFStuf;
In this case You don’t need to do that:
var doStuff = (function(){return IE ? doIEStuf : doFFStuf})();
do You agree ?
At the same time example showed in this post is really “strange” and uses two scopes to do one simple thing … so the goal is not so clear and I can’t understand why getScrollY example should require at least one extra function creation and one call before its assignment.
That’s why I think timing example is even better than getScrollY one :-)
var foo = function() {
return arguments.callee.timestamp = (arguments.callee.timestamp || new Date());
};
function lazy(base, key, fn) {base[key] = function(){
return (this[key] = Constant(fn.apply(this, arguments)))();
};
};
lazy.Constant = function(value) { return function() { return value } };
lazy(this, 'foo', function(){
return + new Date;
});