在函數(shù)內(nèi)部越驻,有兩個特殊的對象:arguments
和 this
宾娜。其中锉走, arguments
的主要用途是保存函數(shù)參數(shù), 但這個對象還有一個名叫 callee
的屬性术徊,該屬性是一個指針本刽,指向擁有這個 arguments
對象的函數(shù)。 請看下面這個非常經(jīng)典的階乘函數(shù):
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}
定義階乘函數(shù)一般都要用到遞歸算法赠涮;如上面的代碼所示子寓,在函數(shù)有名字,而且名字以后也不會變 的情況下笋除,這樣定義沒有問題斜友。但問題是這個函數(shù)的執(zhí)行與函數(shù)名 factorial
緊緊耦合在了一起。為 了消除這種緊密耦合的現(xiàn)象垃它,可以像下面這樣使用 arguments.callee
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1);
}
}
在這個重寫后的 factorial()
函數(shù)的函數(shù)體內(nèi)鲜屏,沒有再引用函數(shù)名 factorial
。這樣嗤瞎,無論引用 函數(shù)時使用的是什么名字墙歪,都可以保證正常完成遞歸調(diào)用。例如:
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
var trueFactorial = factorial;
alert(trueFactorial(5)); //120
factorial = function() {
return 0;
}
alert(trueFactorial(5));// 120 如果沒有使用arguments.callee贝奇,將返 回0
在此虹菲,變量 trueFactorial
獲得了factorial
的值,實際上是在另一個位置上保存了一個函數(shù) 的指針掉瞳。然后毕源,我們又將一個簡單地返回 0的函數(shù)賦值給 factorial
變量浪漠。如果像原來的 factorial()
那樣不使用 arguments.callee
,調(diào)用 trueFactorial()
就會返回 0霎褐≈吩福可是,在解除了函數(shù)體內(nèi)的代 碼與函數(shù)名的耦合狀態(tài)之后冻璃,trueFactorial()
仍然能夠正常地計算階乘响谓;至于factorial()
,它現(xiàn) 在只是一個返回 0的函數(shù)省艳。
現(xiàn)在已經(jīng)不推薦使用arguments.callee()娘纷;
原因:訪問 arguments 是個很昂貴的操作,因為它是個很大的對象跋炕,每次遞歸調(diào)用時都需要重新創(chuàng)建赖晶。影響現(xiàn)代瀏覽器的性能,還會影響閉包辐烂。
不能用怎么辦遏插?
像第三段中的例子,重寫 factorial()
方法導(dǎo)致trueFactorial()
結(jié)果不在預(yù)期纠修。是為了演示而做的胳嘲。平時寫代碼應(yīng)該避免。
遞歸時用到arguments.callee()
是常見的事情分瘾,比如
一道面試題胎围。接受參數(shù)n=5,不用for循環(huán)輸出數(shù)組【1,2,3,4,5】
這用遞歸的思路,配合arguments.callee
德召,代碼如下:
function show(n) {
var arr = [];
return (function () {
arr.unshift(n);
n--;
if (n != 0) {
arguments.callee();
}
return arr;
})()
}
show(5)//[1,2,3,4,5]
現(xiàn)在arguments.callee
被棄用了白魂。怎么辦,其實很簡單上岗,給內(nèi)部函數(shù)一個名字即可:
function show(n) {
var arr = [];
return (function fn() {
arr.unshift(n);
n--;
if (n != 0) {
fn();
}
return arr;
})()
}
show(5)//[1,2,3,4,5]