Function.prototype.toString() 并不总是 return 有效的 JS。为什么?

Function.prototype.toString() does not always return valid JS. Why?

考虑以下 class 声明:

class A {}
A.prototype.test1 = function test1() { console.log("test1") }

评估 test1 的字符串化版本会产生有效的 JS,正如我们在这里看到的:

const a = new A
eval(`(${a.test1})`)() // outputs "test1"

但是,如果我们以不同但基本等效的方式构建 class:

class B {
    test2() { console.log("test2") }
}

评估 test2 的字符串化版本失败:

const b = new B
eval(`(${b.test2})`)() // SyntaxError: Unexpected token {

(它被字符串化为 test2() { console.log("test2") },这不是有效的 JS,除非嵌入在 class 声明中)

我可以理解字符串化的原生函数是不可评估的,例如 "".indexOf.toString() 将 return 一个包含 [native code] 的字符串,我接受。

但是没有办法保证 Function.prototype.toString() 调用用户定义的函数(即源代码可用的函数)产生有效的、可评估的 JS 吗?

But isn't there a way to guarantee that Function.prototype.toString() called on user-defined functions (that is, function from which the source code is available) produces valid, evaluable JS?

没有。这取决于函数的类型。 The specification requires the following:

toString Representation Requirements:

  • The string representation must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, AsyncFunctionDeclaration, AsyncFunctionExpression, ClassDeclaration, ClassExpression, ArrowFunction, AsyncArrowFunction, or MethodDefinition depending upon the actual characteristics of the object.
  • The use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
  • If the object was defined using ECMAScript code and the returned string representation is not in the form of a MethodDefinition or GeneratorMethod then the representation must be such that if the string is evaluated, using eval in a lexical context that is equivalent to the lexical context used to create the original object, it will result in a new functionally equivalent object. In that case the returned source code must not mention freely any variables that were not mentioned freely by the original function's source code, even if these “extra” names were originally in scope.
  • If the implementation cannot produce a source code string that meets these criteria then it must return a string for which eval will throw a SyntaxError exception.

因为你有一个 MethodDefinition 你得到了一个方法的表示。如果你有一个既不是 MethodDefinition 也不是 GeneratorMethod 的函数,那么你可能会得到一个可以 evaluated 的表示(第三点),但即便如此,规范说实现应该 return 抛出语法错误的表示,所以 ¯\_(ツ)_/¯.