Why was the arguments.callee.caller property deprecated in JavaScript?

It was added and then deprecated in JavaScript, but it was omitted altogether by ECMAScript. Some browser (Mozilla, IE) have always supported it and don't have any plans on the map to remove support. Others (Safari, Opera) have adopted support for it, but support on older browsers is unreliable.

Is there a good reason to put this valuable functionality in limbo?

(Or alternately, is there a better way to grab a handle on the calling function?)

推荐答案

Early versions of JavaScript did not allow named function expressions, and because of that we could not make a recursive function 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;
 });

To get around this, arguments.callee was added so we could do:

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

However this was actually a really bad solution as this (in conjunction with other arguments, callee, and caller issues) make inlining and tail recursion impossible in the general case (you can achieve it in select cases through tracing etc, but even the best code is sub optimal due to checks that would not otherwise be necessary). The other major issue is that the recursive call will get a different this value, for example:

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();

Anyhow, EcmaScript 3 resolved these issues by allowing named function expressions, e.g.:

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

This has numerous benefits:

  • The function can be called like any other from inside your code.

  • It does not pollute the namespace.

  • The value of this does not change.

  • It's more performant (accessing the arguments object is expensive).

Whoops,

Just realised that in addition to everything else the question was about arguments.callee.caller, or more specifically Function.caller.

At any point in time you can find the deepest caller of any function on the stack, and as I said above, looking at the call stack has one single major effect: It makes a large number of optimizations impossible, or much much more difficult.

Eg. if we can't guarantee that a function f will not call an unknown function, then it is not possible to inline f. Basically it means that any call site that may have been trivially inlinable accumulates a large number of guards, take:

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

If the js interpreter cannot guarantee that all the provided arguments are numbers at the point that the call is made, it needs to either insert checks for all the arguments before the inlined code, or it cannot inline the function.

Now in this particular case a smart interpreter should be able to rearrange the checks to be more optimal and not check any values that would not be used. However in many cases that's just not possible and therefore it becomes impossible to inline.

Javascript相关问答推荐

查找最长的子序列-无法重置数组

无法访问Vue 3深度监视器中对象数组的特定对象值'

如何使用JavaScript拆分带空格的单词

如何创建返回不带`new`关键字的实例的类

将异步回调转换为异步生成器模式

如何在JAVASCRIPT中合并两组对象并返回一些键

当我try 将值更改为True时,按钮不会锁定

在JS中动态创建对象,并将其追加到HTML表中

在Odoo中如何以编程方式在POS中添加产品

如何在Java脚本中对数据进行签名,并在PHP中验证签名?

用于测试其方法和构造函数的导出/导入类

Reaction useState和useLoaderData的组合使用引发无限循环错误

是否设置以JavaScript为背景的画布元素?

MUI迷你图:如何将$符号添加到MUI迷你图中的工具提示数据

Chart.js Hover线条在鼠标离开时不会消失

设置复选框根据选中状态输入选中值

如何设置时间选取器的起始值,仅当它获得焦点时?

如何在单击链接时设置一个JavaScript变量(以打开弹出窗口的特定部分)

元素类型无效:应为字符串(对于内置组件)或类/函数(对于复合组件),但GET:Object.在Reaction项目中

Jsyaml SafeDump打字支持