代码之家  ›  专栏  ›  技术社区  ›  pcorcoran

为什么JavaScript中不推荐arguments.callee.caller属性?

  •  206
  • pcorcoran  · 技术社区  · 16 年前

    为什么会这样 arguments.callee.caller

    它在JavaScript中被添加,然后被弃用,但ECMAScript完全忽略了它。一些浏览器(Mozilla,IE)一直支持它,并且没有任何计划取消对它的支持。其他浏览器(Safari、Opera)也采用了对它的支持,但在旧浏览器上的支持是不可靠的。

    (或者,是否有更好的方法抓住调用函数的句柄?)

    5 回复  |  直到 11 年前
        1
  •  258
  •   Pacerier    10 年前

    早期版本的JavaScript不允许命名函数表达式,因此我们无法生成递归函数表达式:

     // 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;
     });
    

    然而,这实际上是一个非常糟糕的解决方案,因为这(连同其他参数、被调用方和调用方问题)使得内联和尾部递归在一般情况下不可能实现(您可以通过跟踪等在某些情况下实现它,但即使是最好的代码也是次优的,因为不需要进行检查)。另一个主要问题是递归调用将获得不同的 this

    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通过允许命名函数表达式解决了这些问题,例如:

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

    这有许多好处:

    • 可以从代码内部像调用任何其他函数一样调用该函数。

    • 它不会污染名称空间。

    • 价值 不会改变。

    • 它的性能更高(访问 arguments object 价格昂贵)。

    我才意识到除了其他问题之外 arguments.callee.caller Function.caller .

    如果我们不能保证一个功能 f 不会调用未知函数,则无法内联 F

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

    如果js解释器不能保证在调用时提供的所有参数都是数字,那么它需要在内联代码之前插入所有参数的检查,或者不能内联函数。

        2
  •  89
  •   James Wheare    15 年前

    arguments.call ee .call er Function.call er 所有物( arguments.call ee

    • 函数调用 ,尽管根据ECMA3是非标准的,但在 .
    • arguments.call er 函数调用 ,并且在当前一些主流浏览器(如Firefox3)中没有实现。

    函数调用 属性,可以直接在命名函数引用上访问,也可以通过 参数.调用 ee

        3
  •  29
  •   Zach    16 年前

    命名函数

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

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

    caller 财产:

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

    哪个比什么好

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

    弃用是由于当前ECMAScript design principles .

        4
  •  0
  •   FERcsI    10 年前

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

    第一次调用的阶乘获取对象,但对于递归调用则不是这样。

    推荐文章