为什么在JavaScript中不赞成arguments.callee.caller属性?

为什么在JavaScript中不赞成arguments.callee.caller属性?

它已被添加,然后在JavaScript中被弃用,但它被ECMAScript完全省略。 一些浏览器(Mozilla,IE)一直支持它,并没有任何计划在地图上删除支持。 其他(Safari,Opera)已经采用了对它的支持,但是在旧版浏览器上的支持是不可靠的。

有没有充分的理由把这个有价值的function放在一边呢?

(或者,有没有更好的方法来获取调用函数的句柄?)

JavaScript的早期版本不允许命名函数expression式,因此我们无法创buildrecursion函数expression式:

  // This snippet will work: function factorial(n) { return (!(n>1))? 1 : factorial(n-1)*n; } [1,2,3,4,5].map(factorial); // But this snippet will not: [1,2,3,4,5].map(function(n) { return (!(n>1))? 1 : /* what goes here? */ (n-1)*n; }); 

为了解决这个问题, arguments.callee被添加了,所以我们可以这样做:

  [1,2,3,4,5].map(function(n) { return (!(n>1))? 1 : arguments.callee(n-1)*n; }); 

然而,这实际上是一个非常糟糕的解决scheme,因为它(与其他参数,被调用者和调用者问题一起)在一般情况下使内联和尾recursion变得不可能(你可以通过跟踪等方式在select的情况下实现它,但是即使是最好的代码由于没有其他必要的检查是次优的)。 另一个主要问题是recursion调用会得到不同的值,例如:

 var global = this; var sillyFunction = function (recursed) { if (!recursed) return arguments.callee(true); if (this !== global) alert("This is: " + this); else alert("This is the global"); } sillyFunction(); 

无论如何,EcmaScript 3通过允许命名函数expression式解决了这些问题,例如:

  [1,2,3,4,5].map(function factorial(n) { return (!(n>1))? 1 : factorial(n-1)*n; }); 

这有很多好处:

  • 该函数可以像你的代码中的其他任何东西一样调用。

  • 它不污染名字空间。

  • 这个值不会改变。

  • 这是更高性能(访问参数对象是昂贵的)。

哎呦,

只是意识到,除了其他的一切问题是关于arguments.callee.caller ,或更具体的Function.caller

在任何时候,你都可以find栈中任何函数的最深的调用者,正如我上面所说,看着调用栈有一个主要的影响:它使大量的优化成为不可能的,或者更困难的。

例如。 如果我们不能保证一个函数f不会调用一个未知的函数,那么就不可能内联f 。 基本上,这意味着任何可能被简单地调用的呼叫站点都会聚集大量的警卫,

  function f(a, b, c, d, e) { return a ? b * c : d * e; } 

如果js解释器无法保证提供的所有参数都是调用时的数字,则需要插入对所有参数的检查,或者不能内联函数。

现在在这种情况下,聪明的翻译人员应该能够重新排列检查,使其更为优化,而不是检查任何不会被使用的值。 然而在很多情况下这是不可能的,因此不可能内联。

arguments.call ee .call er 被弃用,虽然它确实使用了Function.call er属性。 ( arguments.call ee只会给你一个当前函数的参考)

  • Function.call er ,尽pipe按照ECMA3标准是非标准的,但是在当前所有的主stream浏览器可以实现。
  • arguments.call er 已经被弃用,而不是使用Function.call er ,并且在一些当前的主stream浏览器(例如Firefox 3)中没有实现。

所以情况并不理想,但是如果你想通过所有主stream浏览器访问JavaScript中的调用函数,你可以使用Function.call er属性,直接访问一个命名的函数引用,或者通过一个匿名函数arguments.call ee属性。

使用命名函数比arguments.callee更好:

  function foo () { ... foo() ... } 

比…更好

  function () { ... arguments.callee() ... } 

指定的函数将通过调用者属性访问其调用

  function foo () { alert(foo.caller); } 

这比…更好

  function foo () { alert(arguments.callee.caller); } 

弃用是由于目前的ECMAScript devise原则 。

仍然有一个参考的function,而不必硬编码的名称。

只是一个扩展。 “this”的值在recursion期间改变。 在以下(修改)的例子中,阶乘获取{foo:true}对象。

 [1,2,3,4,5].map(function factorial(n) { console.log(this); return (!(n>1))? 1 : factorial(n-1)*n; }, {foo:true} ); 

被称为第一次的阶乘获取对象,但对于recursion调用这不是真的。