当前位置: 首页 > 面试题库 >

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

上官凯歌
2023-03-14
问题内容

为什么arguments.callee.caller在JavaScript中不推荐使用该属性?

它是在JavaScript中添加然后弃用的,但ECMAScript完全省略了它。某些浏览器(Mozilla,IE)一直都支持该浏览器,并且在地图上没有删除支持的计划。其他浏览器(Safari,Opera)已对此提供支持,但较旧的浏览器支持不可靠。

是否有充分的理由将这种有价值的功能置于边缘?

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


问题答案:

早期版本的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;
 });

这有很多好处:

  • 可以像在代码内部一样调用该函数。

  • 它不会污染名称空间。

  • 的值this不变。

  • 它的性能更高(访问arguments对象的成本很高)。

Whoops,

刚刚意识到,除了其他所有问题之外,问题还是关于arguments.callee.caller或更具体的问题Function.caller

在任何时间点,您都可以找到堆栈中任何函数的最深层调用者,并且正如我上面所说,查看调用堆栈具有一个主要的作用:它使大量优化变得不可能,甚至更加困难。

例如。如果我们不能保证某个函数f不会调用未知函数,则无法进行内联f。基本上,这意味着任何可能微不足道的呼叫站点都会聚集大量警卫,请采取以下措施:

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

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

现在,在这种特殊情况下,智能解释器应该能够将检查重新排列为最佳状态,而不检查任何不会使用的值。但是,在许多情况下这是不可能的,因此无法内联。



 类似资料:
  • 问题内容: 众所周知,在 Hibernate 5中* 不建议使用 条件查询 。在以前的Hibernate版本中,该功能非常有用。 而且它的性能仍然优于HQL。 * __ 那么它在 Hibernate 5中 被弃用的原因是什么? 这是从这里。 Hibernate提供了一个较旧的旧式API,应将其视为已弃用。没有针对这些API的功能开发。最终,特定于Hibernate的条件功能将被移植为JPA的扩展

  • 问题内容: ControlsFX类被标记为已弃用。 用什么代替呢? 问题答案: 这篇博客文章解释了这一切: http://fxexperience.com/2014/09/announcing- controlsfx-8-20-7/ 自从5月29日发布8.0.6以来,此版本一直在酝酿之中- 基本上是四个月。这对我们来说并不常见(通常我们的发行版要快得多),但是Eugene和我都对一项主要工作分心-

  • 在“Kotlin in Action”中,它说“如果一个成员属性引用了Person类的年龄属性,memberProperty.get(person)是一种动态获取person.age值的方法”,代码为(10.2.1 Kotlin Reflection API): 我不明白为什么这个例子提到“动态”获取属性的值。当我运行以下代码时,它才起作用: 是否有其他成员属性反射的案例或示例?

  • 问题内容: 我继承了其他开发人员编写的一些JavaScript代码。他不喜欢我们在整个项目中使用的网格组件,因此他决定编写自己的网格组件。他写的表格无法对日期进行排序,因为它只能绑定到字符串/数字。他在使用日期之前将所有日期转换为字符串。我查看了他编写的date函数的字符串格式,发现可以将具有原始值的date属性添加到字符串中,然后在排序时查看该字符串是否具有date属性并基于此进行排序。但是,似

  • 问题内容: 在Spring数据REST(通过Spring 1.3.3启动),当我的,资源集合比如说,在不包含在资源属性: 默认情况下,或者在配置Spring Data存储库时: 该是加的更新,并包含在数据行的版本ETag HTTP头,当我查询特定的资源数据。不必GET在集合中的每个资源上调用a ,我更喜欢@Version在集合中获取,GET这样我可以编写我的应用程序来检查每个资源更新的值,而无需执

  • 问题内容: 我最近继承的应用程序关于构造函数的弃用警告已满: 有谁知道或可以指出为什么将诸如以下这样的简单内容替换为以下内容的原因: 现在,显然不赞成使用警告本身并不是问题,但是您是否可以想象,如果删除此构造函数,数以百万计的LOC会痛苦地哭泣吗? 在我对基准测试的简短介绍中,执行基准测试大约需要50%的时间。 问题答案: 本来打算包含有关日期的所有逻辑,但是API设计人员最终意识到,到目前为止,