no-caller
The use of arguments.caller and arguments.callee make code optimizations impossible and are deprecated in ES5 strict mode.
Rule Type: Suggestion
Fixable: No
Why This Rule Exists
- Deprecated: Forbidden in ES5 strict mode
- Performance: Prevents JavaScript engine optimizations
- Security: Can leak function references
- Maintainability: Makes code harder to understand
Rule Details
This rule disallows the use of arguments.caller and arguments.callee.
Examples
Incorrect Code
function foo(n) {
if (n <= 0) {
return;
}
arguments.callee(n - 1);
}
[1,2,3,4,5].map(function(n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
Correct Code
function foo(n) {
if (n <= 0) {
return;
}
foo(n - 1);
}
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
});
Understanding arguments.callee
What It Did
arguments.callee refers to the currently executing function:
function factorial(n) {
return n <= 1 ? 1 : n * arguments.callee(n - 1);
}
Why It’s Bad
accessing arguments.callee prevents inlining and tail call optimization.
// Can't be optimized
const factorial = function(n) {
return n <= 1 ? 1 : n * arguments.callee(n - 1);
};
// Can be optimized
const factorial = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
};
Modern Alternatives
Named Function Expressions
// Instead of arguments.callee
const factorial = function(n) {
if (n <= 1) return 1;
return n * arguments.callee(n - 1);
};
// Use named function expression
const factorial = function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
};
// Or function declaration
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
Arrow Functions
// Can't use arguments.callee anyway (no arguments object)
const factorial = (n) => n <= 1 ? 1 : n * factorial(n - 1);
Array Methods
// Instead of callee in array method
[1,2,3,4,5].map(function(n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
// Use named function
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
});
// Or define function separately
function factorial(n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);
Common Use Cases
Anonymous Recursion
If you need recursion in an anonymous function, give it a name!
// Wrong
setTimeout(function() {
if (condition) {
arguments.callee();
}
}, 1000);
// Right
setTimeout(function retry() {
if (condition) {
retry();
}
}, 1000);
Strict Mode Errors
'use strict';
function test() {
return arguments.callee; // TypeError in strict mode!
}
Y Combinator
// If you really need anonymous recursion (rare)
const Y = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)));
const factorial = Y(f => n => n <= 1 ? 1 : n * f(n - 1));
// Prevents optimization
function slow(n) {
return n <= 0 ? 0 : arguments.callee(n - 1);
}
// Allows optimization (tail call, inlining)
function fast(n) {
return n <= 0 ? 0 : fast(n - 1);
}
Migration Guide
Step 1: Find Usage
grep -r "arguments.callee" src/
grep -r "arguments.caller" src/
Step 2: Add Function Names
// Before
const fn = function(x) {
return x <= 0 ? 0 : arguments.callee(x - 1);
};
// After
const fn = function fn(x) {
return x <= 0 ? 0 : fn(x - 1);
};
Step 3: Test
Ensure recursion still works correctly.
When Not to Use It
This rule should almost never be disabled:
arguments.callee is deprecated
- It’s an error in strict mode
- It prevents optimizations
If you have legacy code that can’t be updated, you may need to disable it temporarily.
Configuration
{
"rules": {
"no-caller": "error"
}
}