views:

104

answers:

2

Can Javascript get a function as text? I'm thinking like the inverse of eval().

function derp() { a(); b(); c(); }

alert(derp.asString());

The result would be something like "a(); b(); c();"

Does it exist?

+6  A: 

Updated to include caveats in the comments below from CMS, Tim Down, MooGoo:

The closest thing available to what you're after is calling .toString() on a function to get the full function text, like this:

function derp() { a(); b(); c(); }
alert(derp.toString()); //"function derp() { a(); b(); c(); }"

You can give it a try here, some caveats to be aware of though:

  • The .toString() on function is implementation-dependent (Spec here section 15.3.4.2)
    • From the spec: An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation string is implementation-dependent.
    • Noted differences in Opera Mobile, early Safari, neither displaying source like my example above.
  • Firefox returns a compiled function, after optimization, for example:
    • (function() { x=5; 1+2+3; }).toString() == function() { x=5; }
Nick Craver
This actually works? Holy shit...
delnan
@delnan - Various objects override the `object.toString()` method, in the case of functions you get the full function text :)
Nick Craver
I knew js was very dynamic, reflective, has first-class functions, etc. But this is... well, I don't know if it's awesome or unnecessary bling-bling. A mix of both, I guess.
delnan
Wow, the code gets pretty formatting added too...!
Brandon
The formatting is a function of the environment you're working in - things like Chrome's JS console or Firebug's console add the formatting.
Amber
@delnan - For the sake of carrying on the bling, there are other less-used properties as well, `derp.length === 0` for the number of arguments, `derp.name === "derp"`, you can `.apply()` or `.call()` it for use in closures (mainly but not exclusively), etc...there is a lot of JavaScript `function`...well, functionality that most people writing it never come across. It's unfortunate, because there's a lot in there, and it's really useful in many cases.
Nick Craver
`name` is non-standard and isn't supported in all browsers. Notable non-supporters include (would you believe) IE.
Tim Down
@Nick, This will work on almost all browsers, but maybe is worth mentioning that the `Function.prototype.toString` method returns an "*implementation-dependent* representation of the function", and in some implementations (Opera Mobile and Older Safari versions IIRC) it will not return the source code of the function, also the `name` property on function objects is *non-standard*.
CMS
@CMS, @Tim - I'm aware it's non-standard, just showing some possible properties, which is why it's in a comment not an answer :) In case anyone's interested in the above you can easily see what is/isn't cross-browser here: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function
Nick Craver
@CMS - The `.toString()` should be safe for current usage if you're using it for display purposes, the spec says it should have the syntax of a function declaration: `function Identifier (FormalParameterList) { FunctionBody }`. So though it's implementation dependent it *should* (as of ECMAscript v3) look like pretty much like the above (with differences in white-space mainly). If a browser (e.g. older Safari) doesn't follow the spec...I tend to see that as the browser's fault.
Nick Craver
It is worth noting that Firefox returns a partially "compiled" version of the body of the function that strips comments, extra whitespace, extra semicolons, and anything else it consideres useless. For instance, `(function() { x=5; 1+2+3; }).toString()` returns `"function () { x = 5; }"`. Most amusingly however is `function() { x=5+4; }` would be returned as `"function () { x = 9; }"`
MooGoo
Thanks guys I made fugly function hooking! http://pastebin.com/07dLguEP
Brandon
@Nick, yes but I think the specification should be more formal, in almost all implementations, the spec. then is not *strictly followed*, for example, an anonymous `FunctionExpression`, like `(function() {}).toString()` returns a string that does *not* represent the grammar of a `FunctionDeclaration`: `"function () {}"`, the mandatory `Identifier` token is missing... BTW I've found the issues where Opera Mobile made [PrototypeJS](http://j.mp/a8cyVa) and [jQuery fail](http://j.mp/bv9yOs).
CMS
@CMS, @Tim, @Moo - Thanks for the comments and examples, I updated the answer to include (hopefully) everything relevant to this question in hopes it gets more eyes than the comments here, these are all great examples to be aware of...if you feel it needs editing go ahead :)
Nick Craver
+1  A: 
function derp() { a(); b(); c(); }

alert(derp.toString());
CD