【问题标题】:How can we know if a function is called from console or from source code我们如何知道函数是从控制台调用还是从源代码调用
【发布时间】:2014-09-17 23:01:19
【问题描述】:

我想知道是否有办法检查是否从浏览器的控制台或源代码调用了 javascript 函数。

我定义了一个函数,可以检查它是来自控制台还是来自页面,但它只适用于谷歌浏览器,它不适用于 Firefox,我没有测试其他浏览器

function fromConsole()
{
    var Caller = arguments.callee.caller;
    while(Caller.caller != null)
        Caller = Caller.caller;
    return (Caller.toString().indexOf("function (expression, objectGroup,"))!=-1;
}

这个函数的工作原理

这个函数查找调用我们函数的顶部函数。在谷歌浏览器中,如果从控制台调用顶部函数的定义在Firefox中包含此字符串function (expression, objectGroup,,则没有函数

让我给你详细解释一下

假设我们有这个例子

function a()
{
    b();
}
function b()
{
    return c();
}
function c()
{
    console.log(fromConsole());
}

如果我们从页面调用函数 a() ,它在控制台中显示为 false (因为顶部函数是 a() )但是,如果我们从控制台调用它,它显示为 true,因为顶部函数是 this " function (expression, objectGroup,..."

在 Firefox 中,无论您是从控制台还是从您的页面调用函数,顶级函数始终是 a()

我的问题是:有没有办法知道函数是否从控制台调用?

【问题讨论】:

  • 我认为“console.error('hello world')”也许可以帮助你。它会像这样在浏览器上回溯:screenshot
  • 在 Firefox 中它不会回溯。我需要一个不能手动完成的功能
  • 你想解决什么问题?
  • 如果您尝试进行某种反作弊,Chrome 允许用户就地编辑 JavaScript,从而可以在代码中添加函数调用。也有代理服务器可以更改传输中的脚本

标签: javascript google-chrome firefox google-chrome-devtools firefox-developer-tools


【解决方案1】:

在 Chrome 中,控制台总是调用中间的 JavaScript 函数,在 Firefox 中,调用直接来自本机代码。因此,您可以在 Chrome 中检查 arguments.callee.caller,但在 Firefox 中它始终是 null。 Safari 在这里的行为与 Firefox 相同,因此检查调用者确实是一种仅适用于 Chrome 的技巧。

您仍然可以检查的是Error.stack property。以下功能适用于 Firefox、Chrome 甚至 Safari:

function fromConsole()
{
    var stack;
    try
    {
       // Throwing the error for Safari's sake, in Chrome and Firefox
       // var stack = new Error().stack; is sufficient.
       throw new Error();
    }
    catch (e)
    {
        stack = e.stack;
    }
    if (!stack)
        return false;

    var lines = stack.split("\n");
    for (var i = 0; i < lines.length; i++)
    {
        if (lines[i].indexOf("at Object.InjectedScript.") >= 0)
            return true;   // Chrome console
        if (lines[i].indexOf("@debugger eval code") == 0)
            return true;   // Firefox console
        if (lines[i].indexOf("_evaluateOn") == 0)
            return true;   // Safari console
    }
    return false;
}

这将向上遍历堆栈,直到找到与控制台对应的条目。这意味着fromConsole() 不需要直接调用,中间可以有任意数量的其他函数调用。不过,它很容易被欺骗,例如通过使用setTimeout():

setTimeout(fromConsole, 0);

这里调用者将是本机超时处理程序,不再指向控制台。

【讨论】:

  • 我不明白的是,如果你在 setTimeout 中调用它并在 chrome 中返回 false,为什么 fromConsole 会返回 true(在 Firefox 中)
  • @Khalid: setTimeout(function(){console.log(fromConsole())}, 0) 在 Firefox 中仍将返回 true,因为调用者是 function(){console.log(fromConsole())} - 这是控制台创建的匿名函数,它在堆栈上也显示为 @debugger eval code。但正如我所说,在 setTimeout(fromConsole, 0) 中,它也会在 Firefox 中为您提供 false
  • 是不是所有情况下都不可能查到??
  • @Khalid:这就是我在回答中所说的。如果您从控制台运行setTimeout(fromConsole, 0);,那么您的代码的调用者就不再是控制台——setTimeout 是。例如,如果有人通过控制台创建 &lt;script&gt; 标记,也会发生同样的事情 - 该脚本可以调用您的函数,而不再是控制台调用它。您只有机会识别来自控制台的直接呼叫。
  • 设置事件参数传递给被调用函数...然后找到调用事件目标 ...event.target
【解决方案2】:

这是一种跨浏览器的方式来查看它是从公共(全局,由 js 控制台调用)还是私有(您的代码)上下文调用的:

(function() { 
    window.f = function() {
        console.log('public')
    } ;
    //f will be this function in the rest of the code in this outer function:
    var f = function() {
        console.log('private'); 
    }
    f();
    //more code here...

}) ()

外部函数中的代码将使用私有函数,而从控制台运行f()将运行公共函数。

【讨论】:

    【解决方案3】:

    对于 Chrome,您只需检查 keys 功能是否可用。它是 chrome 的 Command Line API 的一部分,仅在从控制台执行代码时可用

    function myFunction() {
      var fromConsole = typeof keys === 'function' && keys.toString().indexOf('Command Line API') !== -1
      if (fromConsole) {
        alert('From console')
      } else {
        alert('Not from console')
      }
    }
    

    【讨论】:

    • 我喜欢这种方法,特别是如果每​​个浏览器都有自己的控制台定义函数。
    猜你喜欢
    • 1970-01-01
    • 2016-01-09
    • 2010-10-01
    • 2020-12-02
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2016-10-27
    相关资源
    最近更新 更多