21. Function.prototype.toString revision
This chapter covers the ES2019 feature “Function.prototype.toString
revision” by Michael Ficarra. It brings two major improvements compared to ES2018:
- Whenever possible – source code: If a function was created via ECMAScript source code,
toString()
must return that source code. In ES2016, whether to do so is left up to engines. - Otherwise – standardized placeholder: In ES2016, if
toString()
could not (or would not) create syntactically valid ECMAScript code, it had to return a string for whicheval()
throws aSyntaxError
. In other words,eval()
must not be able to parse the string. This requirement was forward-incompatible – whatever string you come up with, you can never be completely sure that a future version of ECMAScript doesn’t make it syntactically valid. In contrast, the proposal standardizes a placeholder: a function whose body is{ [native code] }
. Details are explained in the next section.
21.1. The algorithm
The proposal distinguishes:
- Functions defined via ECMAScript code:
toString()
must return their original source code.
toString()
may return code that is only syntactically valid within its syntactic context:
> class C { foo() { /*hello*/ } }
> C.prototype.foo.toString()
'foo() { /*hello*/ }'
The following two kinds of line breaks are converted to Unix-style '\n'
:
- Windows:
'\r\n'
- Classic macOS:
'\r'
- Built-in function objects, bound function exotic objects and callable objects which were not defined via ECMAScript code:
toString()
must return a so-called NativeFunction string, which looks as follows.
- Built-in function objects, bound function exotic objects and callable objects which were not defined via ECMAScript code:
"function" BindingIdentifier? "(" FormalParameters ")"
"{ [native code] }"
The parameters can be omitted. If the function is a “well-known intrinsic object” (such as Array
, Error
, isNaN
, etc.) then the initial value of its name
property must appear in the result. Examples:
> isNaN.toString()
'function isNaN() { [native code] }'
> Math.pow.toString()
'function pow() { [native code] }'
> (function foo() {}).bind(null).toString()
'function () { [native code] }'
Functions created dynamically via the constructors
Function
andGeneratorFunction
: engines must create the appropriate source code and attach it to the functions. This source code is then returned bytoString()
.In all other cases (the receiver
this
is not callable): throw aTypeError
.