我们如何知道函数是从控制台调用还是从源代码调用

Posted

技术标签:

【中文标题】我们如何知道函数是从控制台调用还是从源代码调用【英文标题】: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,从而可以在代码中添加函数调用。也有代理服务器可以更改传输中的脚本 【参考方案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')
  

【讨论】:

我喜欢这种方法,特别是如果每​​个浏览器都有自己的控制台定义函数。

以上是关于我们如何知道函数是从控制台调用还是从源代码调用的主要内容,如果未能解决你的问题,请参考以下文章

msbuild 是不是知道它是从 Visual Studio 调用还是从命令行调用?

如何向 C 函数添加分析调用?

当我从 Azure 函数而不是从控制台应用程序运行 LINQ 查询时,它会失败

如何使用解析服务器调用函数

如何知道 Bytebuf 是从 Netty4 中的哪个通道读取的?

从 C++ 调用 DLL 中的函数