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

时间:2017-12-12 14:38:01

标签: javascript ecmascript-6 eval

考虑以下类声明:

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

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

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

但是,如果我们以不同但基本相同的方式构建我们的类:

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

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

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

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

我可以理解字符串化的本机函数不可评估,例如"".indexOf.toString()将返回包含[native code]的字符串,我接受了。

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

1 个答案:

答案 0 :(得分:3)

  

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

没有。这取决于功能的类型。 The specification requires the following

  

toString陈述要求:

     
      
  • 字符串表示必须具有 FunctionDeclaration FunctionExpression GeneratorDeclaration GeneratorExpression AsyncFunctionDeclaration , AsyncFunctionExpression ClassDeclaration ClassExpression ArrowFunction AsyncArrowFunction MethodDefinition 取决于对象的实际特征。
  •   
  • 表示字符串中空格,行终止符和分号的使用和放置取决于实现。
  •   
  • 如果使用ECMAScript代码定义了对象,并且返回的字符串表示形式不是 MethodDefinition GeneratorMethod ,则表示形式必须是如果字符串在词法上下文中使用eval进行求值,该词汇上下文等同于用于创建原始对象的词汇上下文,它将生成一个新的功能等效对象。在这种情况下,返回的源代码不得自由提及原始函数源代码未提及的任何变量,即使这些“额外”名称最初在范围内。
  •   
  • 如果实现无法生成满足这些条件的源代码字符串,则必须返回eval将引发SyntaxError异常的字符串。
  •   

由于您有 MethodDefinition ,因此您可以获得方法的表示。如果你的函数既不是 MethodDefinition 也不是 GeneratorMethod ,那么你很可能得到一个可以eval uated(第三点)的表示,但是即使这样,规范也说实现应该返回一个抛出语法错误的表示,所以¯\_(ツ)_/¯