JavaScript caller 和 callee 属性深度解析与递归陷阱
本文详细解析JavaScript中caller和callee两个属性的定义、行为及区别。caller用于获取调用当前函数的函数引用,顶层调用返回null;callee则指向当前正在执行的函数,常用于匿名函数递归。文章通过代码示例演示了两者在函数调用链中的表现,并重点解决了因变量赋值导致递归中断的问题,提供了使用arguments.callee的标准解决方案。
caller属性:定义与行为
近期在学习JavaScript时遇到了caller和callee的相关问题,通过查阅网络资料并整理总结,特此分享相关知识点。
caller属性:该属性返回一个对调用当前function函数的外部函数对象的引用,使用方式为function.caller。
属性说明:对于普通函数而言,caller属性仅在函数执行期间存在定义。若该函数由顶层代码直接调用,则caller属性值为null。
var time = 3 //控制次数,去掉会一直在caller与handleCaller交替不断执行
function caller() {
caller.caller()//返回调用caller函数的函数引用
}
function handleCaller() {
if (time > 0){
time--
alert(handleCaller.caller)//返回调用handleCaller函数的函数引用
alert(caller.caller)//返回调用caller函数的函数引用
caller()
}
}
handleCaller()
实例分析:在handleCaller首次运行时,两次alert输出均为null。alert(handleCaller.caller)返回null是因为handleCaller由顶层调用;alert(caller.caller)返回null是因为caller的默认初始值为null。随后调用caller()函数,此时caller.caller返回的是调用它的函数(即handleCaller)的引用,通过caller.caller()可再次触发handleCaller。第二次执行handleCaller时,alert(handleCaller.caller)返回caller的代码引用,alert(caller.caller)返回handleCaller的代码。由于调用关系变为handleCaller->caller->handleCaller,两个函数将交替执行。
caller指向调用当前函数的上层函数。需要注意的是,如果函数在全局作用域(即顶层window)中被调用,该属性返回null。接下来通过代码进行验证。
====================
function testCaller(){
if(testCaller.caller == null){
console.log('accessed at global');
}else{
console.log('accessed at ' + testCaller.caller);
}
}
在全局作用域中调用函数。
testCaller(); // accessed at global
在另一个函数内部调用目标函数。
function a(){
testCaller();
}
a(); // accessed at function a(){testCaller();}
此时,testCaller.caller指向的是函数a的定义。
callee属性:递归与引用
callee属性:返回与arguments对象相关联的函数引用,多用于实现匿名函数的递归调用。
属性说明:网络上常见说法称callee返回正在执行的函数引用。具体而言,每个函数都拥有自己的arguments对象,通常用于存储参数。arguments包含一个callee属性,其初始值即为对应自身的函数引用。当函数执行至该语句时,arguments默认对应当前执行的函数,因此arguments.callee即为当前正在执行的函数的引用。若将其他函数的arguments赋值给变量(如示例中的args),则可通过args.callee()重新调用该函数。
function a(){
alert(arguments.callee)
var args = arguments
function c(){
alert(arguments.callee)
args.callee()
}
c()
}
a()
实例分析:示例中arguments.callee默认返回当前正在执行的函数引用(在函数a中返回a自身,在函数c中返回c自身)。通过变量args存储函数a的arguments,并在内置函数c中使用args.callee()再次调用函数a。
====================
function a(x){
if(x<=1)
return x;
else
return x + a(x-1);
}
a(12) // 78
这是一个极简的递归示例,运行结果符合预期。
观察另一种调用方式及其潜在问题。
var b = a;
a = null; // 将a回收
b(12); // erro : 'a' is not a function
原因分析:执行b=a后,b=function a(){}。在调用b之前,执行了a=null。因此,在函数a运行过程中,表达式return x + a(x-1)中的a指向null而非函数a本身。这会导致错误。为解决此问题,需调整函数a的写法。
function a(x){
if(x<=1)
return x;
else
return arguments.callee(x-1); // 这句是改变的地方
}
再次调用修改后的代码。
var b = a;
a = null;
b(12); // 78
原因解释:尽管执行了a=null,但函数a内部并未直接引用变量a,而是通过arguments.callee指向当前正在执行的函数。根据定义,arguments.callee返回正在执行的函数引用,因此递归得以正常进行。
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
