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

Kha*_*lid 5 javascript firefox google-chrome google-chrome-devtools firefox-developer-tools

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

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

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

这个功能如何工作

这个函数查找调用我们函数的top函数.在google chrome中,如果从控制台调用top函数的定义,则function (expression, objectGroup,在firefox中包含此字符串,则没有函数

让我详细解释一下

让我们说我们有这个例子

function a()
{
    b();
}
function b()
{
    return c();
}
function c()
{
    console.log(fromConsole());
}
Run Code Online (Sandbox Code Playgroud)

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

在firefox中,top函数始终是(),您可以从控制台或页面调用函数

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

Wla*_*ant 10

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

你可以检查的是Error.stack财产.以下功能适用于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;
}
Run Code Online (Sandbox Code Playgroud)

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

setTimeout(fromConsole, 0);
Run Code Online (Sandbox Code Playgroud)

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