Why Was the Arguments.Callee.Caller Property Deprecated in JavaScript

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

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.

Arguments.callee is deprecated - what should be used instead?

Yes, that's what, theoretically, should be used. You're right. However, it doesn't work in some versions of Internet Explorer, as always. So be careful. You may need to fall back on arguments.callee, or, rather, a simple:

function callback() {
// ...
setTimeout(callback, 100);
}

setTimeout(callback, 100);

Which does work on IE.

Does Internet Explorer support arguments.callee.name?

Apart from the fact that arguments.callee is effectively being phased out and is completely absent in ECMAScript 5 strict mode, the main issue is that Function objects in IE do not have the name property. It is implemented in some browsers, notably Firefox and recent WebKit-based browsers, but is non-standard, and indeed there is no standardized way to get hold of a function name.

The only option this leaves you is trying to parse the name from the function's string representation, which is not a good idea. There's a (long) discussion here about it: http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/b85dfb2f2006c9f0.

Caller and Calee returns an error

its callee not calee

Warning: The 5th edition of ECMAScript (ES5) forbids use of arguments.callee() in strict mode. Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself. more details on caller callee

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

function showFunc() {
var funcname = arguments.callee.name;
console.log(funcname);
}
showFunc();

accessing the arguments object is expensive.. huh?

The big deal is at least twofold:

1) Accessing the arguments object has to create an arguments object. In particular, modern JS engines don't actually create a new object for the arguments every time you call a function. They pass the arguments on the stack, or even in machine registers. As soon as you touch arguments, though, they have to create an actual object. This is not necessarily cheap.

2) Once you touch the arguments object, various optimizations that JS engines can otherwise perform (e.g. detecting cases in which you never assign to an argument and optimizing that common case) go out the window. Every access to the function arguments, not just ones through arguments becomes much slower because the engine has to deal with the fact that you might have messed with the arguments via arguments.

Why is arguments.callee.caller.name undefined?

Putting a value in an object literal, as you're doing, doesn't affect the value at all.

var foo = {
sendRequest: ...

The function value is only affected by the function expression, which doesn't contain a name.

             ... function() {
alert(bar.getUrl());
}

You need to include the name you want in the function expression itself [fiddle].

var foo = {
sendRequest: function sendRequest() {

How does `arguments.callee` refer to anonymous functions?

am I really calling the same function over and over or are there multiple identical functions called or is something else at play?

Yes, you have only one function instance, which you refer to all the time. However, you are setting up a call stack in which local variables (in your case the argument D) would be saved for every invocation.

why does arguments.caller not point at our function?

There is no caller property on the arguments object, it was removed. You probably meant the caller property of the function object, which is non-standard but still usable (although forbidden in strict mode as well as argments.callee).

Access to callee in arrow functions

How do I access that value from an arrow function? Is it possible?

Short answer is No.

In fact an arrow function don't bind its own this, arguments, super ..., they were meant to provide a shorter syntax with less details, if we check the MDN Reference for Arrow functions we can see that:

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

So you won't be able to get a reference to the function itself with Arrow functions, and as stated in comments arguments.callee "feature" was a pretty bad idea.



Related Topics



Leave a reply



Submit