使用 toString 获取函数名称有什么风险?

What are the risks of using toString to get the name of a function?

由于ES5不支持Function#name. I was looking for a way to emulate that functionality. While a lot of people recommend using Function#toString,其他人强烈反对。

那么使用下面的代码获取函数名有什么风险呢?

if (!Object.hasOwnProperty(Function.prototype, "name")) {
  Object.defineProperty(Function.prototype, "name", {
    configurable: false,
    enumerable: true,
    get: function() {
      var result = /function\s+([^\s(]+)/.exec(this.toString());
      return result ? result[1] : "";
    }
  });
}

由于ES5不支持arrow functions,所以我真的看不出风险在哪里。

作为 ECMAScript 5.1 specification says, the toString method returns a string that has the syntax of FunctionDeclaration:

Function.prototype.toString ( )

An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.

The toString function is not generic; it throws a TypeError exception if its this value is not a Function object. Therefore, it cannot be transferred to other kinds of objects for use as a method.

FunctionDeclaration 具有以下语法:

FunctionDeclaration :

function Identifier ( FormalParameterListopt ) { FunctionBody }

FormalParameterList :

Identifier
FormalParameterList , Identifier

Identifier定义如下:

Identifier ::

IdentifierName but not ReservedWord

IdentifierName ::

IdentifierStart
IdentifierName IdentifierPart

IdentifierStart ::

UnicodeLetter
$
_
\ UnicodeEscapeSequence

IdentifierPart ::

IdentifierStart
UnicodeCombiningMark
UnicodeDigit
UnicodeConnectorPunctuation

结论

虽然这不是一个很好的获取函数名的方法(但是 ES5 中唯一的方法),如果你让它解析上面列出的所有可能性,它可以在 ES5 中安全工作。

但是ES6标准修改了.toString()的规范,这意味着更多可能的语法,使得在其中使用这种方法是不安全的。

所以,只在ES6之前的版本使用此方法