首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

arguments.callee

arguments.callee?属性包含当前正在执行的函数。

描述

callee?是?arguments?对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。

警告:严格模式下,第5版 ECMAScript (ES5)?禁止使用?arguments.callee()。当一个函数必须调用自身的时候, 避免使用?arguments.callee(),?通过要么给函数表达式一个名字,要么使用一个函数声明.

为什么 arguments.callee 从ES5严格模式中删除了?

早期版本的 JavaScript不允许使用命名函数表达式,出于这样的原因, 你不能创建一个递归函数表达式。

例如,下边这个语法就是行的通的:

代码语言:javascript
复制
function factorial (n) {
    return !(n > 1) ? 1 : factorial(n - 1) * n;
}

[1, 2, 3, 4, 5].map(factorial);

但是:

代码语言:javascript
复制
[1, 2, 3, 4, 5].map(function(n) {
    return !(n > 1) ? 1 : /* what goes here? */ (n - 1) * n;
});

这个不行。为了解决这个问题,?arguments.callee添加进来了。然后你可以这么做

代码语言:javascript
复制
[1, 2, 3, 4, 5].map(function(n) {
    return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});

然而,这实际上是一个非常糟糕的解决方案,因为这 (以及其它的?arguments,callee, 和?caller问题) 使得在通常的情况(你可以通过调试一些个别例子去实现它,但即使最好的代码是最理想的,你也没必要去检查调试它)不可能实现内联和尾递归。另外一个主要原因是递归调用会获取到一个不同的?this?值,例如:

代码语言:javascript
复制
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 通过允许命名函数表达式解决这些问题。例如:

代码语言:javascript
复制
[1, 2, 3, 4, 5].map(function factorial(n) {
    return !(n > 1) ? 1 : factorial(n-1)*n;
});

这有很多好处:

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

  • 它具有比访问arguments对象更好的性能

另外一个被废弃的特性是?arguments.callee.caller,具体点说则是?Function.caller。为什么? 额,在任何一个时间点,你能在堆栈中找到任何函数的最深层的调用者,也正如我在上面提到的,在调用堆栈有一个单一重大影响:不可能做大量的优化,或者有更多更多的困难。比如,如果你不能保证一个函数 f 不会调用一个未知函数,它就绝不可能是内联函数 f。基本上这意味着内联代码中积累了大量防卫代码:

代码语言:javascript
复制
function f(a, b, c, d, e) { return a ? b * c : d * e; }

如果 JavaScript 解释器不能保证所有提供的参数数量在被调用的时候都存在,那么它需要在行内代码插入检查,或者不能内联这个函数。现在在这个特殊例子里一个智能的解释器应该能重排检查而更优,并检查任何将不用到的值。然而在许多的情况里那是不可能的,也因此它不能够内联。?

示例

在匿名递归函数中使用?arguments.callee

递归函数必须能够引用它本身。很典型的,函数通过自己的名字调用自己。然而,匿名函数 (通过函数表达式?或者函数构造器?创建) 没有名称。因此如果没有可访问的变量指向该函数,唯一能引用它的方式就是通过?arguments.callee

下面的例子定义了一个函数,按流程,定义并返回了一个阶乘函数。该例并不是很实用,并且几乎都能够用?命名函数表达式实现同样结果的例子, and there are nearly no cases where the same result cannot be achieved with.

代码语言:javascript
复制
function create() {
   return function(n) {
      if (n <= 1)
         return 1;
      return n * arguments.callee(n - 1);
   };
}

var result = create()(5); // returns 120 (5 * 4 * 3 * 2 * 1)

没有替代方案的 arguments.callee

下面的例子是没有可以替代?arguments.callee的方案的,因此弃用它时会产生一个BUG (参看bug?725398):

代码语言:javascript
复制
function createPerson(sIdentity) {
    var oPerson = new Function('alert(arguments.callee.identity);');
    oPerson.identity = sIdentity;
    return oPerson;
}

var john = createPerson('John Smith');

john();

规范

Specification

Status

Comment

ECMAScript 1st Edition (ECMA-262)

Standard

Initial definition. Implemented in JavaScript 1.2

ECMAScript 5.1 (ECMA-262)The definition of 'Arguments Object' in that specification.

Standard

?

ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'Arguments Exotic Objects' in that specification.

Standard

?

ECMAScript Latest Draft (ECMA-262)The definition of 'Arguments Exotic Objects' in that specification.

Living Standard

?

浏览器兼容性

Feature

Chrome

Firefox (Gecko)

Internet Explorer

Opera

Safari

Basic support

(Yes)

(Yes)

61

(Yes)

(Yes)

Feature

Android

Chrome for Android

Firefox Mobile (Gecko)

IE Mobile

Opera Mobile

Safari Mobile

Basic support

(Yes)

(Yes)

(Yes)

8.11

(Yes)

(Yes)

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com