javascript
[Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性
許多js環境都提供檢查調用棧的功能。調用棧是指當前正在執行的活動函數鏈。在某些舊的宿主環境中,每個arguments對象含有兩個額外的屬性:arguments.callee和arguments.caller。前者指向使用該arguments對象被調用的函數。后者指向調用該arguments對象被調用的函數的函數。許多環境支持arguments.callee,但它除了允許匿名函數遞歸地引用自身之外,沒有更多的用途了。(高3中認為使用arguments.callee可以解除函數體內的代碼和函數名之間的耦合,看來也不是完全沒有用的)
圖示
下面是一個簡單的圖示,可以容易了解arguments的callee,caller,及函數的caller
但這個也是特別的有用,可以使用函數名來引用函數自身
function factorial(n){return (n<=1)?1:(n*factorial(n-1)); }arguments.caller屬性更為強大。它指向的是使用該arguments對象調用函數的函數。出于安全考慮,大多數環境已經移除了此特性,因此用它時要檢測一下才行。許多JS環境也提供了一個相似的函數對象屬性--非標準但普遍適應的caller屬性。它指向函數最近的調用者。
function revealCaller(){return revealCaller.caller; } function start(){return revealCaller(); } start()===start;//true;可以利用該屬性獲取一個提供當前調用棧快照的數據結構。構建一個棧跟蹤:
function getCallStack(){var stack=[];for(var f=getCallStack.caller;f;f=f.caller){stack.push(f);}return stack; }使用示例
function f1(){return getCallStack(); } function f2(){return f1(); } var trace=f2();//[f1(), f2()]脆弱性,當某個函數在調用棧中出現不止一次,那么棧檢查邏輯將會陷入循環。
function f(n){return n===0?getCallStack():f(n-1); } var trace=f(1);//問題出在哪?由于函數f遞歸地調用其自身,因此其caller屬性會自動更新,指回到函數f。所以,函數getCallStack會陷入無限地查找函數f的循環之中。即使我們試圖檢測該循環,但在函數f調用其自身之前也沒有關于哪個函數調用了它的信息。因為其他調用棧的信息已經丟失了。
這些棧檢查屬性都是非標準的,在移植性或適用性上很受限制。在ES5的嚴格模式的函數中,它們是被禁止使用的。試圖獲取嚴格函數或arguments對象的caller或callee屬性都將報錯。
最好的策略是完全避免棧檢查。如果檢查棧的理由完全是為了測試,那么更為可靠的方式是使用交互式的調試器。
提示
-
避免使用非標準的arguments.caller和arguments.callee屬性,它們不具備良好的移植性
-
避免使用非標準的函數對象caller屬性,因為在包含全部棧信息方面,它是不可靠的
附錄:這個沒附錄,放水一篇,因為這節實在沒什么可寫的。
轉載于:https://www.cnblogs.com/wengxuesong/p/5570821.html
總結
以上是生活随笔為你收集整理的[Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构-线性表之循环队列
- 下一篇: (计算机组成原理)第三章存储系统-第五节