1. 程式人生 > >callee和caller

callee和caller

在之前的文章中我說到了arguments,現在來說一下他的屬性callee和一個長得相似的雙胞胎弟弟caller:

首先說callee,來一段程式碼:

    var a=function(){
        console.log(arguments.callee);
    }
    var b=function(){
        a()
    }
    b();
這段程式碼在chrome中輸出的是:
ƒ (){
        console.log(arguments.callee);
    }
這個函式和a函式是不是一模一樣?
callee返回正在執行的函式本身的引用。callee是arguments的一個屬性,這個屬性是一個指標,指向這個擁有arguments
物件的函式,
arguments是呼叫函式,那麼這個callee就是呼叫函式的啦)
首先我們來說一個用callee解決的例子,階乘的計算:
  function factorial(num){
        if(num<=1){

        }else{
            return num*factorial(num-1);
        }
    }
上面的程式碼是用的是函式名。上述方法會增強耦合性,為了降低耦合性我們就用callee,而且無論引用函式的時候是什麼名字都可以完成遞迴呼叫。看看callee:
   function factorial(num){
        if(num<=1){
            return 1;
        }else{
            return num*arguments.callee(num-1);
        }
    }
caller:和他相似的我們還有一個caller,es5中規範化了另外一個函式物件屬性caller這個屬性中儲存著呼叫當前的函式的函式引用,如果是全域性作用於中呼叫當前的函式就返回null
function outer(){
        inner();
    }
    function inner(){
1.      alert(arguments.callee.caller);
  2.      alert(inner.caller)
        //上面的這兩行是一樣的1比2 的耦合性更鬆散
     3.   alert(arguments.caller);//undefined
//        3.這行程式碼在嚴格模式下會報錯,但是非嚴格模式下就是undefined
    }
    outer();
//    說是定義argumnets.callee屬性是為了分清qrguments.caller和caller
//    屬性嚴格模式下不能為caller屬性賦值,不然報錯
    // var a=function(){
    //     alert(a.caller);
    // }//定義一個函式。裡面輸出a.caller
    // var b=function(){
    //     a();
    // }//定義一個函式呼叫那個a函式;
    // b();//輸出b函式。
上面的例子中,是呼叫的b根據caller的特性就知道了答案。
    // var a=function(){
    //     alert(a.caller);
    // }//定義一個函式。裡面輸出a.caller
    // var b=function(){
    //     a();
    // }//定義一個函式呼叫那個a函式;
    // a();//null(a在任何函式中被呼叫,即為頂層函式,輸出的就是null),上面的例子一中,a函式是在b中呼叫的所以不是頂層不反悔null,返回當前的呼叫就是b函式啦,而這個例子是在全域性中呼叫的自然是null

最後一個例子幫助深刻地理解頂層:要是a中也有了一個函式
var c=function(){
    alert(c.caller);
}
var a=function(){
    c()
    alert(a.caller);
}
var b=function(){
    a();
}
a();
這個例子在c中的alert出來的是a函式,原因是在a中呼叫。
a中alert出來的是null,畢竟你是在全域性中呼叫的a的函式。b函式相當於沒有用。
好了,這麼多例子都不懂的話,可能是我寫的太差吧。