Storing Property Data In Javascript Function Objects

Posted March 10, 2009 at 9:34 AM by Ben Nadel

Tags: Javascript / DHTML

I was reading up on some jQuery plugin development the other day and I saw something that I had never seen before - someone was storing data as a property of a Javascript function. I have messed around with storing data in the Prototype of a function object, but I've never stored arbitrary data as a property; I didn't even know that one could do such a thing. If you have no idea what I'm talking about, here's a small example:

  • <script type="text/javascript">
  •  
  • // Define a simply method that alerts a property
  • // of itself.
  • function Test(){
  • alert( Test.Data );
  • }
  •  
  • // Define a property on the method.
  • Test.Data = "Method property";
  •  
  •  
  • // Execute the method.
  • Test();
  •  
  • </script>

Notice that we are defining the Test() function and then we are storing a property directly in that function as if the Function object were a standard object (which, in fact, it is). And, when we run this code, it properly alerts:

Method property

There's something really cool about this!

Now, I came across this when looking into jQuery plugin development and the way it was being used there was also very cool; it was being used to store a plugin's default options. It's common in jQuery to be able to pass an options-map into a function that can override a default option set. But, where is the default option set defined? In the example I saw, the default options were being stored as a property of function object itself:

  • <script type="text/javascript">
  •  
  • // Define the jQuery plugin.
  • jQuery.fn.Test = function( objOptions ){
  •  
  • // Use the passed-in option to override any default
  • // option that are provided by the plugin.
  • var objSettings = jQuery.extend(
  • {},
  • jQuery.fn.Test.Default,
  • objOptions
  • );
  •  
  • // Alert the final data value.
  • alert( objSettings.Data );
  •  
  • // Return this for method chaining.
  • return( this );
  • }
  •  
  • // Define the jQuery method's default properties.
  • jQuery.fn.Test.Default = {
  • Data: "Default data"
  • };
  •  
  •  
  • // When the document has loaded, run the plugin.
  • $(
  • function(){
  • $( document ).Test( {} );
  •  
  • }
  • );
  •  
  • </script>

Here, we define our plugin method, then after it, we define a default options map as a property directly on the function itself. Then, when the plugin is executed, we are extending this default property map with the passed-in property map.

How cool is that! I am not sure how I would use this outside of plugin development; but, for jQuery plugin development, this technique seems quite perfect.



Reader Comments

Mar 10, 2009 at 9:51 AM // reply »
14 Comments

Hey, that's a really nice tip Ben. I saw it once, but didn't really bother to go after it and see what it was actually doing. Laziness at the extreme :-)

I've also been playing with some plug-in development in jQuery, and this sure will be useful.


Mar 10, 2009 at 9:54 AM // reply »
9 Comments

The technique is used allow for a wide range of options to be passed into a function, typically as a configuration, without affecting an API's signature/contract. I first saw this in the Ext-JS library and it has been a constant throughout Ext's evolution.

It's also very powerful when combined with Crockford's Module pattern.


Mar 10, 2009 at 9:55 AM // reply »
304 Comments

You call it laziness - I call it efficiency. ;)


Mar 10, 2009 at 9:58 AM // reply »
10,640 Comments

@Marcos,

It's kind of odd to think you can store properties on a variable AND execute it. I guess if you think about parenthesis as operators, it's not so weird... but it's still weird :)


Mar 10, 2009 at 10:02 AM // reply »
10,640 Comments

@Claude,

I'm definitely familiar with the idea of passing in an options object to a method for flexibility - jQuery does this on many things and it is certainly something that I've come to appreciate. What I thought was really cool, though, was how the default settings map was being stored as a property of the function itself - I had never seen this before.

Can you point me in the direction of Crockford's Module pattern. This sounds interesting.


Mar 10, 2009 at 10:16 AM // reply »
9 Comments

You've seen it already in jQuery in the form of namespacing.

YUI Blog: http://yuiblog.com/blog/2007/06/12/module-pattern/

Chris Heilmann: http://www.wait-till-i.com/2007/07/24/show-love-to-the-module-pattern/


Mar 10, 2009 at 11:01 AM // reply »
33 Comments

Not only can you do that but you can have private, privilaged and public members.

http://javascript.crockford.com/private.html


Mar 10, 2009 at 11:07 AM // reply »
10,640 Comments

@Claude,

Thanks, I'll take a look at those links. I am a bit familiar with namespacing in jQuery, but am interested to learn more about how this is used.

@George,

I think the idea of private variables and methods is interesting, but I have not seen a real use for it just yet.


Mar 10, 2009 at 2:15 PM // reply »
29 Comments

Another use of setting properties on a function is memoization. If you have a function that takes a while to run, after the first time it's called you can store or 'memoize' the result. Here's a crude example:

function fn() {
if (!fn.memo) fn.memo = expensiveOperation();
return fn.memo;
}

If you don't like having hardcoded references to the name of your function inside that function's definition, you can also use arguments.callee to get a reference:

function fn() {
var me = arguments.callee;
if (!me.memo) me.memo = expensiveOperation();
return me.memo;
}

This also allows you to get/set properties on anonymous functions!

I highly recommend Googling "javascript memoization" for a slew of terrific articles. Functional programming is an elegant paradigm, and it's making a comeback thanks to JavaScript.


Mar 11, 2009 at 8:31 AM // reply »
10,640 Comments

@David,

Oh that is really cool :) I also totally forgot that you can get the callee from the argument collection. What's lame is that:

console.log( arguments )

... in FireBug does NOT output the callee property. No wonder I forgot about it (hmmph!).

Very cool tip though, thanks.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »