faking it: static method calls in JavaScript
¶ by Rob FrieselHave you ever wanted (as an object-oriented JavaScript developer) to work with an object before you had an instance of it? For example, perhaps there’s a method that you would like to call without going through the overhead of instantiating the object 1. How would you go about doing this? Can you invoke myWidget.doSomeStuff()
if you don’t have an instance of myWidget
yet? Do we have static methods in JavaScript like we do in (for example) Java 2? (HINT: the short answer is “not exactly”.)
First: what are the more traditional options?
A global function. If the mechanics of the function are not specific to the object’s implementation, then this might be a perfectly acceptable approach. If your function is just “doing stuff to” (or “…with”) some arguments then this might be fine. Performing some mathematical operations? Who needs an object-oriented approach for determining Fibonacci numbers? Or trimming whitespace from strings? Certainly that would be overkill.
A namespaced util method. Not too dissimilar from the global function approach; but if you’re namespacing, you’re less likely to have collisions in your variable and function names, and maybe some better sharing of common code, etc 3. As far as “static methods” go, we’re just calling these methods off a singleton–fine (for example) for converting constants, or otherwise working with and manipulating known quantities.
But what about something more sophisticated? What if you have a family of classes (e.g., widget editors) that are all related but may each require an ever so slightly different approach to the context inspection? A global function or namespaced util won’t quite cut it here. What are we to do?
Now it turns out that JavaScript’s prototypal inheritance apparatus provides us with a way to do this. Depending on how you’ve designed and implemented your object classes 4, this could be a relatively trivial operation.
Observe (using our suggested example above):
Nifty, eh?
Imagine a scenario where you have a few dozen classes like this (e.g., each class representing an editor for a specific widget that you might deploy to your WordPress-based blog)–using this technique, each class could perform its own inspection of the context (e.g., the DOM fragment representing the widget) and depending on the outcome of the inspection, assign itself as the appropriate handler 5–and all without creating an instance of a given class until it is needed 6. Marvelous!
But this approach is not without some dangers 7 and does require careful attention to detail and some discipline. Because you’re invoking the specified method from the prototype, you should assume that the method is not “scope safe”. This is not to say that this
is unsafe; but this
might not be what you think it is 8. You can 9 still tap into this
in your “static” method, but you better be damn certain that your this
is what you need it to be and that whatever it is you’re trying to access was declared as part of that object’s prototype. As for the method itself, the arguments passed to the function become of critical importance 10 for how the method returns. But, if you are aware of the possible scope issues, and engineer the “static” method in such a way that it is sufficiently scope agnostic, then invoking methods from the prototype in this manner can be a powerful technique to add to your JavaScript repertoire.
- …only to find out that it’s not even the right object for the task![↩]
- For the record, I’m a Java neophyte; this is the comparison explained to me, and the one that makes sense.[↩]
- But now we’re just talking “best practices”.[↩]
- I won’t go into prototypal inheritance and the various JavaScript constructor patterns here–it’s too big of a subject for this footnote (or even this particular blog post). However, may I recommend familiarizing yourself with “parasitic combination inheritance”, which you may recognize as the
extend()
method from frameworks such as Ext JS or YUI. For a great overview of inheritance and constructor patterns, may I recommend chapter 6 of Nicholas Zakas’ Professional JavaScript for Web Developers[↩] - We’re (of course?) assuming here that there is a 1:1 binding relationship between editors and widgets for the sake of this example.[↩]
- Granted, in this example, there still needs to be some apparatus in place to manage calling the inspector method from each prototype (bringing us right back around to the “global function and/or namespaced util” question) but depending on the specifics of the implementation, there’s actually an opportunity to cache or curry the results from the inspection. And/but this is not at all to diminish the huge advantage you get from having the class’ method actually on the class; everything you need to know about the class is that it exists (and it takes care of the rest).[↩]
- As many JavaScript developers have discovered by their “journeyman” stage, messing around with the prototype of a given object is not for the faint of heart.[↩]
- That is to say, if you think
this
is an instance, then you’d be mistaken–and you’d be missing the whole point of trying this method in the first place.[↩] - …and for maximum effectiveness probably should.[↩]
- But when aren’t the arguments important…?[↩]
Leave a Reply