Function.prototype.toString spec
On 02/12/2007, Peter Michaux <petermichaux at gmail.com> wrote:
ECMA-262 3rd == section 15.3.4.2 == Function.prototype.toString returns a representation with syntax of FunctionDeclaration == section13 == FunctionDeclaration: function Identifier ( FormalParameterList_opt ) { FunctionBody } FunctionExpression: function Identifier_opt ( FormalParameterList_opt ) { FunctionBody }
== Firefox results == alert((function(){}).toString()) // outputs function () { }
This is one area where there's some browser incompatibility. To discuss some different syntaces too:
Saf 3.0.4: Function(); // => "function anonymous()\n{\n ;\n}"
Ie 6 (w/ JScript 5.7): Function(); // => "function anonymous() { \n }"
Kestrel: Function(); // => "function (){}"
Merlin: Function(); // => "function ()\n{\n }"
Ff2: Function(); //=> "function anonymous() {\n}"
Ff3b1: Function(); //=> "function anonymous() {\n}"
However, if the function has a name "anonymus", you'd expect that variable name to refer to the function object, right? It doesn't, it's a ReferenceError.
Let's do a little more in-detail analysis in browsers:
function literalise(str){
return '"'+(String(str)
.replace(/\u005c/g,'\\u005c')
.replace(/\u000a/g,'\\u000a')
.replace(/\u000d/g,'\\u000d')
.replace(/\u0022/g,'\\u0022'))+'"';
}
var
div=document.createElement('div');
str='var
u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));', divContents='<button onclick="'+str.replace(/\u0022/g,'"')+'">event</button>', fn=function(){var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));} window.literalise=literalise; div.innerHTML=divContents; document.documentElement.lastChild.appendChild(div); Function(str)(); setTimeout(str,10); fn();
Merlin/Linear_B: Function(str): argument.callee : "\u000afunction ()\u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}\u000a" anonymous : "undefined" onclick : "undefined" setTimeout(str,10): argument.callee : "undefined" anonymous : "undefined" onclick : "undefined" fn: argument.callee : "\u000afunction ()\u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}\u000a" anonymous : "undefined" onclick : "undefined" onclick: argument.callee : "\u000afunction (event)\u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a}\u000a" anonymous : "undefined" onclick : "\u000afunction (event)\u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}\u000a"
Kestrel/Futhark: Function(str): argument.callee : "function (){var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));}" anonymous : "undefined" onclick : "undefined" setTimeout(str,10): argument.callee : "undefined" anonymous : "undefined" onclick : "undefined" fn: argument.callee : "function(){var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));}" anonymous : "undefined" onclick : "undefined" onclick: argument.callee : "var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));" anonymous : "undefined" onclick : "var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));"
Ie6/JScript5.7: Function(str): argument.callee : "function anonymous() {\u000avar u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));\u000a}" anonymous : "undefined" onclick : "undefined" setTimeout(str,10): argument.callee : "function anonymous()\u000a{\u000avar u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));\u000a}" anonymous : "undefined" onclick : "undefined" fn: argument.callee : "function(){var u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));}" anonymous : "undefined" onclick : "undefined" onclick: argument.callee : "function anonymous()\u000a{\u000avar u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));\u000a}" anonymous : "undefined" onclick : "function anonymous()\u000a{\u000avar u='undefined';prompt('arguments.callee',literalise(typeof arguments===u?u:arguments.callee));prompt('anonymous',literalise(typeof anonymous===u?u:anonymous));prompt('onclick',literalise(typeof onclick===u?u:onclick));\u000a}"
Saf3.0.4b/JavaScriptCore: Function(str): argument.callee: "function anonymous() \u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "null" setTimeout(str,10): (Broken? Had to change the prompt to alert to display these...) argument.callee: "undefined" anonymous: "undefined" onclick: "null" fn: argument.callee : "function () \u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous : "undefined" onclick : "null" onclick: argument.callee: "function onclick(event) \u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "function onclick(event) \u000a{\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}"
Ff3.0b1/SpiderMonkey: Function(str): argument.callee: "function anonymous() {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "undefined" setTimeout(str,10): argument.callee: "undefined" anonymous: "undefined" onclick: "undefined" fn: argument.callee : "function () {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous : "undefined" onclick : "undefined" onclick: argument.callee: "function onclick(event) {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "function onclick(event) {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}"
Ff2.0.0.11/SpiderMonkey: Function(str): argument.callee: "function anonymous() {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "undefined" setTimeout(str,10): argument.callee: "undefined" anonymous: "undefined" onclick: "undefined" fn: argument.callee : "function () {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous : "undefined" onclick : "undefined" onclick: argument.callee: "function onclick(event) {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}" anonymous: "undefined" onclick: "function onclick(event) {\u000a var u = \u0022undefined\u0022;\u000a prompt(\u0022arguments.callee\u0022, literalise(typeof arguments === u ? u : arguments.callee));\u000a prompt(\u0022anonymous\u0022, literalise(typeof anonymous === u ? u : anonymous));\u000a prompt(\u0022onclick\u0022, literalise(typeof onclick === u ? u : onclick));\u000a}"
Note there is no Identifier in this output and an identifier is required in FunctionDeclaration syntax. Should Function.prototype.toString be specified to return a representation with FunctionExpression syntax?
IMO, if the serialisation includes a name, that name should be usable as a variable reference within it. So the serialisation should never include a name if it's not there.
However, this simple rule falls apart for several reasons, most important that function declarations are bound in the outside scope only, and not on the inside scope at all. This means a dissociated function object from a function declaration will no longer be able to use the original name as a reference to itself.
Aware of it. This has been resolved in favor of making the spec say (effectively) "FunctionDeclaration or FunctionExpression".
ECMA-262 3rd
== section 15.3.4.2 ==
Function.prototype.toString returns a representation with syntax of FunctionDeclaration
== section13 ==
FunctionDeclaration: function Identifier ( FormalParameterList_opt ) { FunctionBody }
FunctionExpression: function Identifier_opt ( FormalParameterList_opt ) { FunctionBody }
== Firefox results ==
alert((function(){}).toString())
// outputs
function () { }
Note there is no Identifier in this output and an identifier is required in FunctionDeclaration syntax. Should Function.prototype.toString be specified to return a representation with FunctionExpression syntax?
Thanks, Peter