详解javascript function中的caller,callee,call,apply
caller
返回一个对函数的引用,该函数调用了当前函数。也就是说,返回的是调用该函数的函数。
functionName.caller
functionName 对象是所执行函数的名称。
说明
对于函数来说,caller 属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。值得注意的一点是,事件的触发总是带着一个匿名的函数。
点击查看--caller测试示例
callee
返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文,他是arguments对象的一个属性。[function.]arguments.callee,可选项 function 参数是当前正在执行的 Function 对象的名称。
说明
callee 属性的初始值就是正被执行的 Function 对象。
callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用,这有利于匿名函数的递归或者保证函数的封装性,例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。还有需要注意的是callee拥有length属性,这个属性有时候用于验证还是比较好的。arguments.length是实参长度,arguments.callee.length是形参长度,由此可以判断调用时形参长度是否和实参长度一致。
点击查看--callee测试示例
apply and call
它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式有所区别:
apply(thisArg,argArray);
call(thisArg[,arg1,arg2…] ]);
即所有函数内部的this指针都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的
apply的说明
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisArg任何一个参数,那么 Global 对象将被用作 thisArg,并且无法被传递任何参数。
call的说明
call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisArg指定的新对象。如果没有提供 thisArg参数,那么 Global 对象被用作 thisArg
相关技巧:
应用call和apply还有一个技巧在里面,就是用call和apply应用另一个函数(类)以后,当前的
函数(类)就具备了另一个函数(类)的方法或者是属性,这也可以称之为“继承”。
点击查看--call 和 apply 测试示例
?
=====================================================================
基础练习,call,apply,caller,callee,prototype
<!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.0?Transitional//EN"> ?
<html>
?<head>
??<title>?New?Document?</title>
??<meta?name="Generator"?content="EditPlus">
??<meta?name="Author"?content="">
??<meta?name="Keywords"?content="">
??<meta?name="Description"?content="">
??<meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>
??<script?type='text/javascript'>
??//<![CDATA[
//---------------------arguments?demo---------------------
function?argDemo(a,?b){
????var?i,?msg?=?"The?argDemo?function?expected?";
????var?numargs?=?arguments.length;????//获取被传递参数的数值
????var?expargs?=?argDemo.length;????????//获取期望参数的数值
????if?(expargs?<?2){
????????msg?+=?expargs?+?"argument.";
????}else{
????????msg?+=?expargs?+?"arguments.";
????}
????if?(numargs?<?2){
????????msg?+=?numargs?+?"was?passed.";
????}else{
????????msg?+=?numargs?+?"were?passed.";
????}
????msg?+=?"\n\n";
????for?(i?=?0;?i?<?numargs;?i++?){????????//获取参数内容
????????msg?+=?"?arg"?+?i?+?"?=?"?+?arguments[i]?+?"\n";
????}
????alert(msg);
????return?msg;
}
function?testArg(){
????alert(argDemo);
????argDemo("aaa","bbb");
}
//---------------------?caller?demo?---------------------
function?callerDemo()?{
????if?(callerDemo.caller)?{
????????var?a=?callerDemo.caller.toString();
????????alert("the?caller?is?\n"?+?a);
????}?else?{
????????alert("this?is?a?top?function");
????}
}
function?handleCaller()?{
????callerDemo();
}
function?handleCaller2(){
????callerDemo();
}
function?testCaller(){
????alert(callerDemo);
????alert(testCaller);
????callerDemo();
????alert(handleCaller);
????handleCaller();
????alert(handleCaller2);
????handleCaller2();
}
//---------------callee?demo--------------
function?calleeDemo(){
????alert(arguments.callee);
}
//用于验证参数
function?calleeLengthDemo(arg1,?arg2){
????if?(arguments.length?==?arguments.callee.length){
????????window.alert("验证形参和实参长度正确!");
????}else{
????????alert("实参长度="?+?arguments.length?+?"\n形参长度="?+?arguments.callee.length);????
????}
}
//递归
var?calleeSum?=?function(n){
????if?(n?<=?1){
????????return?1;
????}else{
????????return?n?+?arguments.callee(n?-?1);????
????}
}
var?calleeSum2?=?function(n){
????if?(n?<=?1){
????????return?1;
????}else{
????????return?n?+?calleeSum2(n?-?1);????
????}
}
function?testCallee(){
????alert(calleeDemo);
????calleeDemo();
????alert(calleeLengthDemo);
????calleeLengthDemo("aabb");
????alert(calleeSum);
????alert("calleeSum="?+?calleeSum(5));
????alert(calleeSum2);
????alert("calleeSum2="?+?calleeSum2(5));
}
//-------------call?apply------------------
function?callBase(){
????this.member?=?"callbase's?property";
????this.method?=?function(){
????????alert("base:"+this.member);
????}
}
function?callExtend(){
????callBase.call(this);
????alert(member);
????alert("extend:"?+?this.method);
}
function?testCall(){
????alert(callExtend);
????callExtend();????
}
var?applyShow?=?function?(s){
????alert(s);
}
function?applyDemo(){
????applyShow.apply(this,arguments);
????alert(this.applyShow);
}
function?testApply(){
????applyDemo("hahahahah");
}
//-----------------prototype?继承---------------------
var?Class?=?{
????create:?function(){
????????return?function(){this.initialize.apply(this,?arguments);}
????}
}
var?testClass?=?Class.create();
testClass.prototype={
????initialize:?function(name){
????????this.name?=?name;
????},
????al:?function(){
????????this.show.apply(this,arguments);
????},
????al2?:?function(){
????????return?function(){
????????????alert("this.show?=?\n"?+?this.show);
????????????this.applyShow.apply(this,arguments);
????????};
????},
????show:?function(s){
????????alert(s+"ccc"+this.name);
????}
}
function?testPrototype(){
????var?c?=?new?testClass("gemini");
????c.al("aaaa");
????c.al2()("zzzzz");
}
??//]]>
??</script>
?</head>
?<body>
?<input?type='button'?value='测试Arguments'?onclick='testArg();'?/><br?/>
??<input?type='button'?value='测试Caller'?onclick='testCaller();'?/><br?/>
??<input?type='button'?value='测试Callee'?onclick='testCallee();'?/><br?/>
??<input?type='button'?value='测试Call'?onclick='testCall();'?/><br?/>
??<input?type='button'?value='测试Apply'?onclick='testApply();'?/><br?/>
??<input?type='button'?value='测试Prototype'?onclick='testPrototype();'?/><br?/>
???</body>
</html>
?