I've noticed in javascript that if you define a function, say myfunction(), and then call myfunction.toString() you get the text of the source for that function. Are there any interesting/real world uses of this?
One real-world example is in Prototype, which uses this to determine the names of the arguments to methods in subclasses to see if it should do its special superclass handling stuff (which involves the special argument $super
).
apart from the usefulness of getting the content of a function as a string, or ensuring that the type of whatever you're working is a string (for non coercive comparisons), check out the optional radix parameter that can be used.
radix Optional. Specifies a radix for converting numeric values to strings. This value is only used for numbers.
var a = 16;
a.toString(2) // returns "10000"
a.toString(4) // returns "100"
a.toString(8) // returns "20"
a.toString(16) // returns "10"
a.toString(32) // returns "g"
The following example illustrates the use of the toString method with a radix argument. The return value of function shown below is a Radix conversion table.
function CreateRadixTable (){
var s, s1, s2, s3, x; //Declare variables.
s = "Hex Dec Bin \n"; //Create table heading.
for (x = 0; x < 16; x++) //Establish size of table
{ // in terms of number of
switch(x) // values shown.
{ //Set intercolumn spacing.
case 0 :
s1 = " ";
s2 = " ";
s3 = " ";
break;
case 1 :
s1 = " ";
s2 = " ";
s3 = " ";
break;
case 2 :
s3 = " ";
break;
case 3 :
s3 = " ";
break;
case 4 :
s3 = " ";
break;
case 5 :
s3 = " ";
break;
case 6 :
s3 = " ";
break;
case 7 :
s3 = " ";
break;
case 8 :
s3 = "" ;
break;
case 9 :
s3 = "";
break;
default:
s1 = " ";
s2 = "";
s3 = " ";
} //Convert to hex, decimal & binary.
s += " " + x.toString(16) + s1 + x.toString(10)
s += s2 + s3 + x.toString(2)+ "\n";
}
return(s); //Return entire radix table.
}
Well, you can use it to easily redefine a function:
function x() { alert('asdf'); }
eval(x.toString().replace('asdf','hello'));
x();
This will alert the string "hello" instead of the string "asdf".
This may be useful. On the other hand, self modifying code is often frowned upon because of the difficulty to maintain it...
I've used it to automatically generate named-parameter versions of functions. For example, if you have a function
function f(a, b, c) {
return a * b + c;
}
you can extract the parameter names from f.toString()
and use it to generate a function that you can call like this:
namedParametersF({ a: 2, b: 3, c: 4}); // f(2, 3, 4);
Here's an implementation of this idea:
// Get an array of parameter names from a function
Function.parameters = function(f) {
// Find the parameter list in f.toString()
var m = /function[^\(]*\(([^\)]*)\)/.exec(f.toString());
if (!m) {
throw new TypeError("Invalid function in parameters");
}
var params = m[1].split(',');
for (var i = 0; i < params.length; i++) {
// trim possible spaces
params[i] = params[i].replace(/^\s*|\s*$/g, '');
}
return params;
};
// Convert f to a function that accepts named parameters
Function.withNamedParameters = function(f) {
var params = Function.parameters(f);
return function(args) {
var argsArray = new Array(params.length);
for (var i = 0; i < params.length; i++) {
argsArray[i] = args[params[i]];
}
return f.apply(this, argsArray);
};
};
I have a slightly more flexible implementation of this that can go the other direction (Function.withPositionalParameters
) on GitHub: http://gist.github.com/132782.