本文详细解析JavaScript中call、apply、caller和callee四个核心属性的用法。通过实例演示如何利用call和apply改变函数执行上下文及传递参数,将伪数组转换为真数组,并对比两者在参数传递形式上的差异。同时深入讲解caller如何追踪函数调用者,以及callee在匿名函数递归中的应用,帮助开发者深入理解JS函数机制。
call与apply基础用法对比
本文通过具体实例,深入解析JavaScript中call、apply、callee以及caller这四个关键概念的实际应用。内容旨在帮助读者更好地理解这些特性,并提供参考代码供学习使用。
在第一个实践中,重点展示call和apply如何使一个对象调用原本不属于它的方法。这两个方法均支持参数传递,主要区别在于参数格式:call要求参数以列表形式逐个列出,而apply则要求参数以数组形式传入。
var person = {
"name":"Tom",
"say":function(){
console.log("person say");
},
"count":function(x,y,z){
console.log('x= ' + x + ', y= ' + y + ', z= ' + z);
},
"sayName":function(){
console.log(this.name);
}
}
// 下面的示例是数组 arr 去调用person的say方法 , 这里call用来让数组调用本不属于它自己的方法
var arr = [1,2];
person.say.call(arr);
// call 还可以传递参数
person.count.call(arr,1,2,3); // x= 1, y= 2, z= 3
// apply 还可以这样
person.count.apply(arr,[1,2,3]); // x= 1, y= 2, z= 3
利用call和apply修改this指向
第二个实践聚焦于利用call和apply修改函数内部this的指向。此处继续沿用前文提到的person对象作为示例,演示如何通过这两个方法改变执行上下文。
var program = {"name":"AlphaGo"}
person.sayName.call(program); // AlphaGo
person.sayName.apply(program); // AlphaGo
将伪数组转换为真数组
第三个实践展示了如何利用call和apply将伪数组(如arguments对象或类数组对象)转换为真正的数组。
// call,apply 把伪数组转换为数组
var wArr = {0:"hello",1:"world","length":2};
var arr1 = Array.prototype.slice.call(wArr);
var arr2 = Array.prototype.slice.apply(wArr);
console.log(arr1); // [hello,world]
console.log(arr2); // [hello,world]
关于伪数组的更多详细信息,可参考专门介绍伪数组的文章。
arguments对象特性分析
第四个实践单独探讨arguments对象的行为特性,不涉及call或apply,仅关注其自身属性。
// 有关arguments
function count(a,b,c){
console.log(arguments.length);
if(count.length === arguments.length) {
console.log('实际参数与形参个数相同');
}else{
console.log('实际参数与形参个数不同');
}
}
count(1,2,3); // 实际参数与形参个数相同
count(1,2); // 实际参数与形参个数不同
/*
这里count.length 表示形参个数
arguments.length 表示实参个数
*/
使用caller追踪函数调用者
第五个实践介绍caller属性的用途,即用于查看当前函数是被哪个外部函数调用的。
function fn1(){
if(fn1.caller){
console.log(fn1.caller.name + " 是函数fn1的调用者");
}else{
console.log("直接执行");
}
}
function fn2(){
fn1();
};
fn2(); // fn2是是函数fn1的调用者
利用callee实现匿名函数递归
第六个实践讲解callee属性,它返回当前正在执行的Function对象。这一特性常与arguments配合使用,特别是在处理匿名函数的递归调用时非常有用。
var sum = function(n){
if(n>0) {
return n + arguments.callee(n-1);
}
return 0;
};
var total = sum(10);
console.log(total); // 55
// arguments.callee 代指函数自身。
function test(){
console.log(arguments.callee);
}
test(); // 输出函数自身的字符串表达式
感兴趣的用户可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun对上述代码进行测试,以直观观察运行效果。
如需了解更多JavaScript相关知识,建议查阅本站系列教程,包括《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》以及《JavaScript数学运算用法总结》。
希望本文所述内容能对各位JavaScript程序设计师有所帮助。