【问题标题】:How do you find out the caller function in JavaScript when use strict is enabled?启用 use strict 后,如何找出 JavaScript 中的调用者函数?
【发布时间】:2015-06-16 19:46:24
【问题描述】:

启用use strict后是否可以看到函数的被调用者/调用者?

'use strict';

function jamie (){
    console.info(arguments.callee.caller.name);
    //this will output the below error
    //uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
};

function jiminyCricket (){
   jamie();
}

jiminyCricket ();

【问题讨论】:

  • 一般情况下(很少例外)如果你想这样做 - 你做错了什么。试着用这段代码解释你想解决的真正的问题。
  • 别无选择。推荐的方式是直接使用函数名,如jamie.name // jamie。但是函数名称通常是无关紧要的,除了用于调试之外,它们对您的代码没有任何影响,并且依赖此功能而不是递归通常是一个 XY 问题。
  • 说实话,我的代码没有任何真正的问题,但我有一个函数别名 console.info 所以 c = console.info 本质上。因此,当我使用所述功能控制台某些东西时,它只会在控制台中显示它每次都来自同一个地方。我想输出调用它的函数。只是因为我的懒惰和酷都合二为一:D
  • ye 当然 :) 但这意味着按 f11 .... 如果一点代码可以为我做到这一点,我不想再做任何事情:p 我是一名程序员..这是我这样做的唯一原因...我很懒
  • This MDN document 解释了为什么将其从 JS 严格模式中删除。基本上,使用 arguments.callee 和 arguments.caller 的能力使某些 JS 引擎优化变得困难/不可能。

标签: javascript use-strict


【解决方案1】:

对于它的价值,我同意上面的 cmets。无论您要解决什么问题,通常都有更好的解决方案。

但是,仅出于说明目的,这里有一个(非常丑)解决方案:

'use strict'

function jamie (){
    var callerName;
    try { throw new Error(); }
    catch (e) { 
        var re = /(\w+)@|at (\w+) \(/g, st = e.stack, m;
        re.exec(st), m = re.exec(st);
        callerName = m[1] || m[2];
    }
    console.log(callerName);
};

function jiminyCricket (){
   jamie();
}

jiminyCricket(); // jiminyCricket

我只在 Chrome、Firefox 和 IE11 中测试过这个,所以你的里程可能会有所不同。

【讨论】:

  • 有个好主意。抛出错误。这真的没什么大不了的。很高兴知道 console.log 的来源。我不认为这是一个问题?
  • 这很好用。我们不得不使用 throw 版本而不是 @inetphantom 的解决方案,因为我们必须使用的嵌入式 JavaScript 引擎在 Error().stack 被抛出之前不会填充它。
  • 您好,请问有什么方法可以获取调用函数的参数吗?
  • @easa 我认为不会有一个通用的解决方案。你真的需要在调试器中检查堆栈。
  • 你投了赞成票,因为丑陋而聪明让我发笑
【解决方案2】:

请注意,这不应该在生产中使用。这是一个丑陋的解决方案,对调试很有帮助,但是如果您需要调用者提供的东西,请将其作为参数传递或将其保存到可访问的变量中。

@p.s.w.g 答案的简短版本(没有抛出错误,只是实例化一个):

    let re = /([^(]+)@|at ([^(]+) \(/g;
    let aRegexResult = re.exec(new Error().stack);
    sCallerName = aRegexResult[1] || aRegexResult[2];

完整片段:

'use strict'

function jamie (){
    var sCallerName;
    {
        let re = /([^(]+)@|at ([^(]+) \(/g;
        let aRegexResult = re.exec(new Error().stack);
        sCallerName = aRegexResult[1] || aRegexResult[2];
    }
    console.log(sCallerName);
};

function jiminyCricket(){
   jamie();
};

jiminyCricket(); // jiminyCricket

【讨论】:

  • 与堆栈中的名称匹配的正则表达式可能应该是([^(]+) 而不是(\w+),因为空格和标点符号很常见。
  • 您添加了生产使用警告...嗯...该功能确实不纯。但这应该是不在生产代码中使用它的一个重要原因吗?代码似乎很稳定(据我判断)。一个非常有趣的应用程序是日志记录方法。在这种情况下,在参数中传递调用者名称将是乏味、臃肿且容易出错的。因此,在我看来,为什么以及何时应该在生产中使用某些代码的决定主要取决于软件设计和一些常识。如果它适合我​​,我会很乐意在生产代码中使用它。
  • 啊。我现在明白了。 Error.prototype.stack 属性被正式标记为非标准且特定于实现。
  • From the Error.prototype.stack documentation on MDN: "不同的浏览器在不同的时间设置这个值。例如,Firefox 在创建 Error 对象时设置它,而 PhantomJS 仅在抛出错误时设置它,归档的 MSDN 文档也似乎与 PhantomJS 实现相匹配。”所以p.s.w.g 的答案(涉及创建、抛出和捕获错误)可能会更加健壮......
  • @BartHofland 我仍然不会使用它-记录谁调用了函数的意义在哪里?如果有错误 - 记录该错误。
【解决方案3】:

它对我不起作用 这是我最终要做的,以防万一它对某人有所帮助

function callerName() {
  try {
    throw new Error();
  }
  catch (e) {
    try {
      return e.stack.split('at ')[3].split(' ')[0];
    } catch (e) {
      return '';
    }
  }

}
function currentFunction(){
  let whoCallMe = callerName();
  console.log(whoCallMe);
}

【讨论】:

  • 你能解释一下为什么这对你有用而其他解决方案没有?
  • 我在 aRegexResult[1] 索引超出范围时遇到了类似异常
  • aregexResult[1] index out of range 是因为调用堆栈中与\w+ 不匹配的名称被跳过。你应该改用[^(]+。
  • 这个解决方案应该比 Regex 快得多。
  • 这似乎最适合 Angular/TypeScript 配置。
【解决方案4】:

您可以使用以下方法获取堆栈跟踪:

console.trace()

但如果您需要对调用者做某事,这可能没有用。

见https://developer.mozilla.org/en-US/docs/Web/API/Console/trace

【讨论】:

    【解决方案5】:
      functionName() {
        return new Error().stack.match(/ at (\S+)/g)[1].get(/ at (.+)/);
      }
    
      // Get - extract regex
      String.prototype.get = function(pattern, defaultValue = "") {
        if(pattern.test(this)) {
          var match = this.match(pattern);
          return match[1] || match[0];
        }
        return defaultValue; // if nothing is found, the answer is known, so it's not null
      }
    

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 2012-02-15
      • 2013-06-13
      • 1970-01-01
      • 2014-02-17
      • 2016-08-20
      • 2015-11-29
      • 2016-12-15
      相关资源
      最近更新 更多