本系列作為Effective JavaScript的讀書筆記。
由于歷史原因,很多JavaScript執(zhí)行環(huán)境中都提供了某些方式來(lái)查看函數(shù)調(diào)用棧。在一些環(huán)境中,arguments對(duì)象(關(guān)于該對(duì)象可以查看Item 22,23,24)上有兩個(gè)額外的屬性:
arguments.callee - 它引用了正在被調(diào)用的函數(shù)
arguments.caller - 它引用了調(diào)用當(dāng)前函數(shù)的函數(shù)
關(guān)于arguments.callee的使用,可以參考下面的代碼:
可見,在遞歸函數(shù)中,可以使用callee來(lái)得到當(dāng)前正在被調(diào)用的函數(shù)。
但是,使用函數(shù)聲明的方式也可以很方便的實(shí)現(xiàn)函數(shù)的遞歸調(diào)用,并且這種方式更加清晰:
而對(duì)于arguments.caller,它提供的功能就更加強(qiáng)大了,能保存了調(diào)用當(dāng)前函數(shù)的函數(shù)的一個(gè)引用。因?yàn)樗邪踩[患,所以很多JavaScript運(yùn)行環(huán)境都將這個(gè)屬性移除了。同時(shí),有部分運(yùn)行環(huán)境在函數(shù)對(duì)象上提供了一個(gè)caller屬性來(lái)達(dá)到和arguments.caller相同的效果:
因此,可以利用這個(gè)屬性來(lái)得到當(dāng)前調(diào)用棧的信息:
對(duì)于簡(jiǎn)單的調(diào)用關(guān)系,上述確實(shí)能夠得到調(diào)用棧的信息:
但是當(dāng)一個(gè)函數(shù)在調(diào)用棧中出現(xiàn)不止一次時(shí),就會(huì)發(fā)生問(wèn)題了,比如下面的代碼會(huì)產(chǎn)生一個(gè)死循環(huán):
原因在于,當(dāng)發(fā)生遞歸調(diào)用時(shí),函數(shù)自身會(huì)被賦值給它的caller屬性。因此getCallStack中的for循環(huán)的終止條件f永遠(yuǎn)不會(huì)為false:
正因?yàn)檫@種不穩(wěn)定性和由此帶來(lái)的安全性問(wèn)題,在ES5的strict mode中,使用caller或者callee屬性都是被禁止的:
總結(jié):