Arguments.callee已被弃用 - 应该使用什么代替?

43

对于像这样的事情

setTimeout(function () {
    ...
    setTimeout(arguments.callee, 100);
}, 100);

我需要类似于arguments.callee的东西。我在javascript.info上找到了相关信息,它已经被ECMA-262弃用:

出于更好的性能和支持命名函数表达式的考虑,这个属性已经被标记为过时。

那么应该使用什么代替呢? 类似于这样吗?

setTimeout(function myhandler() {
    ...
    setTimeout(myhandler, 100);
}, 100);
// has a big advantage that myhandler cannot be seen here!!! 
// so it doesn't spoil namespace

顺便问一下,arguments.callee在所有浏览器中都兼容吗?


2
说句题外话:具名函数表达式的解密 - sdleihssirhc
是的,您应该为函数命名并在setTimeout中使用其名称。 - kubetz
1
@cHao,不是重复的问题:arguments.callee.caller弃用并不意味着整个arguments.callee都被弃用。此外,这个问题并没有问“应该使用什么代替!” - Tomas
@Tomas:请检查答案。你所问的一切都在答案中提到了。 - cHao
3个回答

11

是的,从理论上讲,应该使用这个。should。你是对的。但是,像往常一样,在某些版本的Internet Explorer中它不起作用。所以要小心。你可能需要退而求其次使用arguments.callee或者简单地:

function callback() {
    // ...
    setTimeout(callback, 100);
}

setTimeout(callback, 100);

这在IE上有效。


1
等等 - 你想说 setTimeout(function myhandler() { setTimeout(myhandler ... 在某些 IE 版本中无法运行?这是非标准的吗?我以为这是一个相当标准的做法。 - Tomas
3
@TomasT.:这是标准的,但是IE从来没有完全符合标准吧?(好吧,也许IE10例外。)我记得有一段时间被这个问题绊倒过。快速测试表明,至少在IE7中不是问题。可能是IE6的问题。我没有设备来测试。 - Ry-
根据微软的说法,它在IE6中可以工作:https://learn.microsoft.com/en-us/scripting/javascript/reference/callee-property-arguments-javascript - Jack G
@lolzerywowzery:那是arguments.callee,而不是命名函数表达式。我记得在IE中有三个命名函数表达式的阶段:完全不工作,泄漏到周围范围,以及按规范工作。 - Ry-

5

1

minitech的回答非常好,但是它缺少一个场景。您声明了名为callback的函数,这意味着两件事:首先,该函数是内存中的对象,其次,函数名称仅用于引用对象。如果由于任何原因打破这两者之间的引用,建议的代码也将无法工作。

证明:

function callback() {
    // ...
    setTimeout(callback, 100);
}

setTimeout(callback, 100);

var callback2 = callback; //another reference to the same object
callback = null; //break the first reference
callback2(); //callback in setTimeout now is null.

描述中来自Mozilla开发者页面的内容如下:

警告:ECMAScript(ES5)第5版禁止在严格模式下使用arguments.callee()。 通过为函数表达式命名或在必须调用自身的函数处使用函数声明来避免使用arguments.callee()。

显然,这是解决方法的第一个例子“通过为函数表达式命名”,但让我们看看如何处理“或在必须调用自身的函数处使用函数声明”以及这将会带来什么:

function callback(){
   //...
   setTimeout(innercall(), 100);
   function innercall(){
      //innercall is safe to use in callback context
      innercall.caller(); //this will call callback();
   }
}

那么我们可以放心地对回调引用进行任何操作:

var callback2 = callback;
callback = null;
callback2(); //will work perfectly.

“caller” 不是一个好的实践,而且这里的示例代码似乎并没有设置超时。不要覆盖你声明的函数。 - Ry-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接