What are these Foo$Bar$baz functions in the Microsoft Ajax Library files?

If you've looked at the debug version of our JavaScript files, you may have noticed code similar to that:

Foo.Bar = function Foo$Bar() {
	Foo.Bar.initializeBase(this);
}
function Foo$Bar$baz() {
	// Do something
}
Foo.Bar.prototype = {
	baz: Foo$Bar$baz
}
Foo.Bar.registerClass('Foo.Bar');	

And looking at that, you may have wondered what the Foo$Bar$baz names were for. That's a very good question and I congratulate you on your thoroughness. Here's why:
Stack trace shows anonymous functions

"JScript anonymous function"? That's not very helpful in a debugger stack trace and that's what you'd get if we had written the above code this way (or run the release version of the script):

Foo.Bar = function() {
	Foo.Bar.initializeBase(this);
}
Foo.Bar.prototype = {
	baz: function() {
		// Do something
	}
}
Foo.Bar.registerClass('Foo.Bar'); 

In this case, the methods on class instances are anonymous methods.

Thanks to the global "dollared" names that we inject into the debug code, the functions have a global name that is easy to map to the actual member that they are aliases for, and here's what a typical stack trace looks like in debug mode:
Stack trace shows meaningful function names

That's of course a lot more useful. Of course, you should never use those names in code that consumes those libraries, as they are here only to make debugging easier and they won't be there if you run the release versions of the scripts (which you are doing on your production servers, right?). For example, Foo$Bar$baz in the above example is an alias for Foo.Bar.prototype.baz, which is what you should use if you need it. Most of the time, you'll just call baz off an instance, like this: myBar.baz().

Finally, you may wonder why we're not writing this (which would be more compact and maybe a little easier to read):

Foo.Bar = function Foo$Bar() {
	Foo.Bar.initializeBase(this);
}
Foo.Bar.prototype = {
	baz: function Foo$Bar$baz() {
		// Do something
	}
}
Foo.Bar.registerClass('Foo.Bar'); 

Well, that would be great, but our good friend Safari 2 refuses to parse it... Safari 3 seems to fix that bug though.

12 Comments

  • Kevin: that's just the way it is. JavaScript functions don't know what they've been assigned to. You could even point several different variables to the same function reference (actually, it happens all the time with prototype functions that are referenced by instances). The debugger has no way of knowing what you consider to be the relevant assignment. All it has is the global name that was given to the function when it was declared, and that's exactly what we're leveraging here.

  • Does the ASP.NET Ajax team plan to release the "compression" tool they use to create the release script from the debug script?

  • Are you saying that Safari will not run scripts with the function body inline or that it simply won't show the stack?

  • Scott: that's good feedback, we're getting that question a lot. We're thinking about it, but it takes some time. Thanks.

  • Steven: Safari refuses to parse "baz: function Foo$Bar$baz()" if it's inside an object literal declaration like the prototype declaration. IIRC, it's considered a syntax error.

  • Kinda off topic...

    Is it not the case that functions prefaces with "_" are by convention private methods? I could be completely off here, but if so, how can we use "Function._validateParams(...);" in our own client class libraries code to validate arguments as they come into our methods?

    Thx!!

  • George: yes, it is private/internal, but you wouldn't be the only one to use it. You have to know that being private, there is a small chance that it could change in the future. So, at your own risk...

  • Perhaps this bit of guidance could be added to the AJAX documentation at some point.

  • Thx!

    Is there a public function that is available for validating parameters? If not, was it left off b/c the method's signature might change in the future and you guys didn't want to risk a breaking change? It seems that it's a very valuable feature that JavaScript lacks (being argument agnostic) and would compliment the framework nicely.

  • Can you do up a small sample of how this $ method should be used for debug scripts and not for production scripts?

  • Kori: typically, you'd have the following release code for the above example:
    Foo.Bar=function(){Foo.Bar.initializeBase(this);}Foo.Bar.prototype={baz:function(){/*Do something*/}}Foo.Bar.registerClass('Foo.Bar');
    In other words, the $ names are compeltely absent from the release scripts. Does this help?

  • Joel: we still support Safari 2 and will do so at least until Safari 3 has been released in its final version and has reasonable adoption.
    I'll update the post though. Thanks for the heads up.

Comments have been disabled for this content.