【问题标题】:Get function name from instantiated function从实例化函数中获取函数名
【发布时间】:2016-03-01 04:40:12
【问题描述】:

如何在不知道其名称的情况下从其内部获取实例化 JavaScript 函数的名称?

我需要它的原因是因为我开始处理异常,并且我想稍后将异常的名称作为字符串获取,而无需手动将名称写入异常函数本身,就像在 MDN 文档中的示例中一样: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/throw

示例:

function MyException(message) {
    this.message = message;
    this.name = 'MyException';  // How to get function name automatically?
    this.toString = function() {
        return this.name + ': ' + this.message;
    };
}

try {
    throw new MyException('Hello world');
}
catch (e) {
    alert(e);  // "MyException: Hello world"
}

Function.name,但是一旦函数被实例化(通过new 运算符)它就不能使用,因为函数随后变成了一个没有任何属性或方法的对象。

【问题讨论】:

  • 您可以使用拆分 toString() 的 getter 填充 IE9+ 的 .name,或者只记录 toString()
  • 我不明白。如何?没有name 属性并且toString() 方法只返回[object Object],因为此时MyException 不再是一个函数(它之前通过new 运算符转换为一个对象)。请举例说明你的意思吗?
  • 您可以使用实例的constructor 属性来获取函数...
  • 嗯...是的。这将规避 callee 的严格模式问题。这是一个额外的解决方案,但我更喜欢只编写一次提取代码(使用继承),而不是一次又一次地编写所有异常。否则,如果发生变化,就需要修改每一个异常函数。但你是对的 - 我没有想到构造函数属性。谢谢。

标签: javascript


【解决方案1】:

函数提供arguments 对象,其中包含callee 属性,这是一个指向调用函数的指针(请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/argumentshttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee)。所以arguments.callee是同一个实例化函数(现在是对象)的原始函数。

ECMAScript 2015 引入了 Function.name 属性 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name),Chrome、Opera、Firefox 和 Safari 支持但在 Internet Explorer 中不支持(在我的 IE11 中是 undefined),因此通过arguments.callee.name 适用于所有浏览器,IE 除外。

但是,有一个小技巧可以通过为 Function.prototype 属性创建一个辅助方法(因此它被所有函数继承)从所有浏览器中的实例化函数(然后是对象)内部获取名称,然后提取来自已经可用的toString() 方法的函数名:

Function.prototype.getName = function()
{
    var funcName = this.toString().substr(9);
    return funcName.substr(0, funcName.indexOf('(')).trim();
};

function MyException(message) {
    this.message = message;
    this.name = arguments.callee.getName();  // Get orig. function name
    this.toString = function() {
        return this.name + ': ' + this.message;
    };
}

try {
    throw new MyException('Hello world');
}
catch (e) {
    alert(e);  // "MyException: Hello world"
}

注 1:不支持匿名函数,因为它们没有名称。但是可以使用命名函数:

var MyException = function MyException(message) {
    // ...
}

注意 2:arguments.callee 在 ES5 严格模式下不可用。

注 3:我使用了String.prototype.trim()trim 方法,该方法在 IE9+ 中可用。如果不可用,请创建一个 shim:

if (!String.prototype.trim)
{
    String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); };
}

【讨论】:

  • 这适用于function F(){ console.log('F'); },但不适用于var F = function (){ console.log('F'); }
  • 因为在您的示例中,您创建了一个没有名称的匿名函数。您可以像这样使用命名函数:var F = function F(){console.log('F'); }。但是感谢您的注意,我已将其添加到答案中。
  • 请注意,在某些(希望是旧的且不再使用的)versions of IE 中,命名函数表达式在引用该函数的封闭范围(通常是全局)中创建了一个变量。
【解决方案2】:

访问Function.name属性,关注支持的浏览器列表,如果适合你就好了)

function MyException(message) {
    this.message = message;
    this.name = MyException.name;  // 'MyException'
    this.toString = function() {
        return this.name + ': ' + this.message;
    };
}

【讨论】:

  • Function.name 在 IE 中未定义。而且我不想在其中再次写入函数名称(否则我可以使用问题中示例中的字符串版本)。
猜你喜欢
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 2021-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多