這兩個關鍵字在平時編碼中幾乎難以用到,但它們既然存在於javascript語言體系中,那么還是有必要了解下。
caller是javascript函數類型的一個屬性,它引用調用當前函數的函數
function func() { alert(func.caller); } function func1() { func(); } func1();
比如上面的代碼, 因為func函數是杯func1函數調用的, 所以func函數中對caller的引用就是func1函數。如果func函數直接在頂層的javascript環境中被調用,那么caller將返回null。
我們可以利用caller的特性跟蹤函數的調用鏈
function func() { let caller = func.caller; while(caller != null) { console.log(caller.name); caller = caller.caller; } } function func1() { func(); } function func2() { func1(); } function func3() { func2(); } func3();
以上代碼將func3到func的函數調用鏈打印出來。
callee則不是函數對象的屬性,它是函數上下文中arguments對象的屬性
function func() { alert(arguments.callee); }
它引用的是函數自身,在上面的代碼中,arguments.callee引用的就是func函數本身。既然他引用的是函數本身,那么似乎顯得有點多余,當我們需要在函數體內使用函數本身時,直接通過函數名調用就可以了,干嘛還要多此一舉的通過arguments.callee這樣去調用。然而我覺得callee存在的意義可能是想解耦函數本身對函數名稱的依賴吧, 比如說在遞歸的環境下,函數內部通常還要調用函數本身, 而調用函數本身就免不了硬編碼函數名稱, 如果函數名稱有變化, 那么函數中的代碼也需要修改,使用callee就可以避免此類情況。
function factorial( num ) { if( num == 1 ) { return 1; } let result = num * factorial(num - 1); return result; } alert(factorial(100));
上面的階乘函數通過callee可以改造成
function factorial( num ) { if( num == 1 ) { return 1; } let result = num * arguments.callee(num - 1); return result; } alert(factorial(100));
如此同樣實現遞歸, 但是可以做到函數體不依賴函數名稱
