栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

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

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

早期版本的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 :  (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解释器不能保证在调用时提供的所有参数都是数字,则它需要在内联代码之前插入对所有参数的检查,否则它不能内联函数。

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



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/415929.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号