caller、callee是與javascript函數相關的兩個屬性,今天來總結下。
Function.caller
caller是javascript函數的一個屬性,它指向調用當前函數的函數,如果函數是在全局范圍內調用的話,那么caller的值為null。
function outer() { inner(); } function inner() { if(inner.caller==null) { //值為null,在全局作用域下調用 console.log("我是在全局環境下調用的"); } else { console.log(inner.caller+"調用了我"); } } inner(); outer();
arguments.callee
arguments是函數內部中一個特殊的對象,callee是arguments的屬性之一, 他指向擁有該arguments的函數對象。在某些不方便暴露函數名的情況下, 可以用arguments.callee代替函數名。但是,在嚴格模式(“use strict;”)下訪問arguments.callee會拋出 TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 錯誤
現在我們來仔細看看上面那段代碼。如果老板說:“不行,函數名叫inner不好聽,給我改!” 改代碼容易,但是想改了后不出錯誤那可就難了。 這時我們就可以使用argument.callee來代替函數名,減少修改代碼的地方,從而降低出錯率
function outer() { inner(); } function inner() { //只需改這個函數名,而不需要改內部代碼 if(arguments.callee.caller==null) { console.log("我是在全局環境下調用的"); } else { console.log(arguments.callee.caller+"調用了我"); } } inner(); outer();
除此之外,當我們寫遞歸函數時,也會在函數里面暴露函數名,此時也會產生問題,如下。
/** * factorial:階乘 */ function factorial(n) { if(n<=1) { return 1; } else { return n*factorial(n-1); } } console.log(factorial(3)); //6 var foo = factorial; console.log(foo(3)); //6 factorial = null; console.log(foo(3)); //Error:factorial is not a function
factorial置為null,雖然foo指向了factorial使其不會被銷毀, 但是原函數內部的函數名任然是factorial,自然應找不到而報錯。 此時我們就可以用arguments.callee代替函數名
function factorial(n) { if(n<=1) { return 1; } else { return n*arguments.callee(n-1); } }
那還能不能更強點?畢竟arguments.callee在嚴格模式下是無法訪問的,肯定沒法兒用啊!
var factorial = (function foo(n) { if(n<=1) { return 1; } else { return n*foo(n-1); //內部可訪問foo } }); foo(6); //ReferenceError: foo is not defined
以上代碼利用命名函數表達式的形式創建了一個遞歸函數。 這有兩個好處:第一,嚴格模式下函數任然能照常運轉; 第二,性能優於argument.callee。注意foo僅在其函數體內可訪問,在外是訪問不到的。
arguments.caller
arguments.caller 這是我們遇到的第二個caller,沒啥用,在嚴格模式下無法訪問,非嚴格模式下值也為undefined,而且貌似被廢棄了
總結
1.Function.caller指向調用該函數的函數
2.arguments.callee指向擁有該arguments的函數
3.arguments.caller沒啥用
引用
1.《javascript高級程序設計》
2.MDN
2.1 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
2.2 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller
2.3 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee