【问题标题】:How does `arguments.callee` refer to anonymous functions?`arguments.callee` 如何引用匿名函数?
【发布时间】:2012-09-18 12:33:44
【问题描述】:

需要一个脚本来快速告诉我页面上有多少个 html cmets 以及它们的内容是什么。使用匿名函数进行递归 DOM 遍历似乎很合适:

var comments = []; //set up an array where comment contents will be copied to

(function(D) {
  if (8===D.nodeType) comments.push(D.nodeValue); //check if node is a comment
  D=D.firstChild;
  while (D) {
    arguments.callee(D); //recursively look for comments...
    D=D.nextSibling; //...and remember to iterate over all children of any node
  }
})(document);

console.log(comments.join("\r\n")); //list all comments

Fiddle 按预期工作,但我很好奇它是否真的是同一个函数被一遍又一遍地调用,或者是否有多个对调用的原始函数的引用,或者是否有多个相同的函数称为...毕竟,没有命名引用,那么随着遍历的深入,它将如何工作?我想我可以通过将the following code 添加到while (D) {...} 中来检查这一点

//tmpCallee has been declared
if (tmpCallee) {
  console.warn(arguments.callee === tmpCallee);//true
  /*great, means these should be both pointing to the same function*/
  console.log(arguments.callee === arguments.caller);//false
  /*wait, what? didn't we just establish above that 
    all of our functions called recursively would be the same?*/
  console.log(arguments.caller);//undefined... but it was called recursively!
  console.log(arguments.callee);//prints our function code verbatim as it should
}
tmpCallee = arguments.callee;

我很困惑。 1) 我是 真的 一遍又一遍地调用同一个函数,还是调用了多个相同的函数,还是有其他东西在起作用? 2)为什么arguments.caller指向我们的函数?它显然是由它调用的——这就是递归的工作原理,不是吗?

【问题讨论】:

  • 您可以将函数命名为:(function fn (D) {,然后是 while (D) { fn(D); ...。不需要 已弃用 arguments.callee...
  • 正如 Šime Vidas 所说。只是想补充一点,arguments.callee 在严格模式下不起作用。
  • 我并不是说命名函数会是首选选项,但这种特定行为背后的逻辑是什么?我找不到任何文档,而且看起来真的很奇怪 - 因此问题
  • 参数没有任何调用者属性。你应该改用arguments.callee.caller。

标签: javascript recursion anonymous-function


【解决方案1】:

我真的是一遍又一遍地调用同一个函数,还是调用了多个相同的函数,还是有其他东西在起作用?

是的,你只有一个函数实例,你一直引用它。但是,您正在设置一个调用堆栈,其中将为每次调用保存局部变量(在您的情况下为参数D)。

为什么 arguments.caller 没有指向我们的函数?

arguments 对象上没有caller 属性,它是removed。您可能指的是函数对象的caller property,它是非标准的但仍然可用(尽管在严格模式以及argments.callee 中被禁止)。

【讨论】:

  • 感谢您的指正,arguments.callee === arguments.callee.caller 返回 true,一切恢复正常!
【解决方案2】:

这里只涉及一个函数实例。该函数递归调用自身。您可以通过为代码中的函数表达式指定名称来轻松检查这一点:

(function fn (D) {

然后,在体内:

fn === arguments.callee // => true

上述对于每一个调用都是正确的,表明在这个过程中只创建和调用了一个函数。

还有,这个:

arguments.callee === arguments.callee.caller // => true, except first time

向您展示该函数调用自身,即调用者是被调用者。上述表达式对于除第一次调用外的所有调用都是正确的,因为第一次调用发生在全局代码中。

现场演示: http://jsfiddle.net/HbThh/2/

【讨论】:

  • 当然这在函数命名时会更清晰/可读;不正确的arguments.callee === arguments.caller 只是误导我认为匿名函数的机制会有所不同
【解决方案3】:

arguments 没有caller 属性,您应该使用arguments.callee.caller 来获取caller

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 2011-07-27
    • 2023-04-10
    相关资源
    最近更新 更多