2

有没有办法从外部获取函数的名称?

假设网页上有一个我们无法修改的 js 脚本,只需阅读即可。该脚本包含对象,其中包含对象和函数。假设我们要查找名为“HelloWorld”的函数。

使用 firebug,我们使用脚本循环这些对象和方法,看起来像这样

// Parameter is target object.
function getFunctionNames(obj) {

    // For each objects / functions
    for (var id in obj) {

        // Focus only on functions
        if (typeof(obj[id]) == "function") {

            // Get name of the function.
            // console.log("Function: " + obj[id].toString()); 

            // Code above returns a block of code without the name. Example output:
            // Function: function(name) { alert("Hello World! Hello " + name + "!"); }
            //
            // Expected output would be
            // Function: HelloWorld
        }
    }
}
  • obj[id].toString()返回代码块而不是名称。
  • obj[id].name返回一个空字符串。匿名函数(?)。
  • 我不能使用arguments.callee.name因为我不能修改目标代码。

可以只在 firebug 中浏览对象和函数,或者只阅读源代码,但我正在寻找一种使用 Javascript 的方法。

编辑

对于现实世界的例子,前往Youtube并尝试通过 Javascript 从“yt”对象获取函数“setMsg()”的名称。

编辑2

接受西蒙的答案,因为它有点接近我正在寻找的东西。看来我是在寻找变量名,而不是函数名。虽然答案对原始问题没有帮助,但它肯定回答了原始问题。Paul Draper 的评论帮助我找到了正确的方向。

谢谢!

4

2 回答 2

2

利用obj.name

注意arguments.callee返回一个函数name是每个函数的属性(尽管对于匿名函数它是空的),所以这就是arguments.callee.name有效的原因。

这适用于 webkit(Chrome 和 Safari)、Firefox,可能还有其他。它不适用于 IE:在 IE 中不支持 function.name。

于 2013-11-03T00:31:13.480 回答
1

""如前所述,该函数除了从匿名函数中获得的名称外,没有任何内在名称。然而,一些浏览器(Firefox,可能是 Chrome,可能还有其他浏览器)会执行一些有限形式的静态分析来找出声明函数的名称,以帮助跟踪错误堆栈。setMsg您可以通过抛出异常然后解析以相对跨浏览器的方式获取它exc.stack

// cheat with .% in Firebug; there might be other ways of doing this, I dunno:
yt.setMsg.%m.za.__defineSetter__('a', function() { throw new Error(); });

try { yt.setMsg('a', 'a'); }
catch(e) { alert(e.stack.split('\n')[2].split('@')[0]); }

...另一方面,这是一个非常糟糕的 hack,并且取决于所涉及的实际功能(如果您知道该功能,您可能已经知道它的名称)。从函数内部完成时,它确实工作得更可靠一些。

如果您将自己限制为仅使用 Firefox 并且出于调试目的而这样做,那么有更好的方法来实现它。在 about:config 中设置devtools.chrome.enabled为 true,打开 Scratchpad (Shift+F4),将其设置为 environment: browser,然后运行以下命令:

Components.utils.import("resource://gre/modules/jsdebugger.jsm");
window.addDebuggerToGlobal(window);

dbg = new Debugger();
dw = dbg.addDebuggee(content);

f = content.wrappedJSObject.yt.setMsg;
name = dw.makeDebuggeeValue(f).displayName;

dbg.removeDebuggee(content);

alert(name);

在这两种情况下,您都会注意到它警告的是“m.ya”而不是“setMsg”,这实际上是因为该函数最初被声明为m.ya = function() { ...; }. 从浏览器的角度来看,“setMsg”没有理由成为一个更可取的名称。

于 2013-11-03T12:00:09.600 回答