關於如何取消匿名函數的綁定以及arguments.callee的用法

之前在看《JavaScript高級程序設計》第十三章P391看到關於arguments.callee的用法, 然後又翻回之前的內容, 原來在第5章引用類型P113的時候曾經講到過這個arguments.callee, 發現這個arguments對象的屬性其實有挺大的用處的, 接下來講一講的兩大作用:

作用一. 取消代碼與函數名的耦合狀態

首先, 如果要定義一個階乘函數, 大多數人都會這樣寫:

  1. function factorial(num){
  2.    if( num  <= 1){
  3.       return 1;
  4.    }
  5.    else{
  6.       return num * factorial (num - 1);
  7.    }
  8. }

這種寫法確實可以實現效果, 但問題是這個函數的執行與函數名factorial緊緊耦合在了一起, 而且在如下代碼調用的時候會出現錯誤:

  1. var trueFactorial = factorial;
  2. factorial = function(){
  3.    return 0;
  4. };
  5. alert(trueFactorial(5));              //0
  6. alert(factorial(5));                     //0

在此, 變量trueFactorial獲得了factorial的值, 實際上實在另一個位置保存了一個函數的指針. 然後,我們又將一個簡單地返回0的函數賦值爲factorial變量. 那麼當第5行調用了trueFactorial時, 走到上一塊代碼中方法定義的第6行, return num * factorial (num - 1); 那麼此時factorial( num - 1)返回的結果就是0了, 那麼此時這個 factorial方法就不再有計算階乘的功能了, 那麼如何解決這個問題呢? 可以像下面這樣重新定義factorial方法:

  1. function factorial(num){
  2.    if(num <= 1){
  3.       return 1;
  4.    }
  5.    else{
  6.       return num * arguments.callee(num - 1);
  7.    }
  8. }

那麼現在執行如下代碼時的結果就不同了:

  1. var trueFactorial = factorial;
  2. factorial = function(){
  3.    return 0;
  4. };
  5. alert(trueFactorial(5));              //120
  6. alert(factorial(5));                     //0

爲什麼呢? 首先trueFactorial = factorial的意思並不是讓trueFactorial指向factorial, 而是把factorial引用的函數傳遞給trueFactorial, 所以說此時trueFactorial的方法定義如下面這樣:

  1. if(num <= 1){
  2.       return 1;
  3.    }
  4.    else{
  5.       return num * arguments.callee(num - 1);
  6.    }

因此, 當代碼運行到第5行時, 不會像以前那樣執行那個return 0的factorial函數了, 而是通過arguments.callee執行當前這個作用於中arguments對象所屬的那個函數, 也就是trueFactorial !! 由於此時trueFactorial的方法定義仍然是一個計算階乘的函數, 因此當傳入參數爲5時返回的結果就是120! 可以看到arguments.callee的作用是解除了函數體內代碼與函數名的耦合狀態, 從而實現在函數名發生變化或者函數的定義發生變化時不會受到影響.

作用二. 取消匿名函數的綁定

以前當我們通過addEventListener或者attachEvent等方法爲元素綁定事件處理程序時, 如果綁定的是匿名函數, 那麼在正常情況下是沒有辦法解除綁定的, 也就是說沒辦法取消事件綁定, 那麼假如我們通過如下方式來綁定事件處理程序:

  1. var num = 1;
  2. var oDiv = document.getElementById('myDiv');
  3. oDiv.addEventListener( ' click ' , function(){
  4.     alert(num);
  5.     num++;
  6.     if( num == 3 ){
  7.         oDiv.removeEventListener( 'click', arguments.callee);
  8.     }
  9. });

如果像上面這樣執行代碼時, 可以發現當我點擊id爲myDiv的元素兩次時, 會分別彈出警告框提示1、2, 然而點擊第3次的時候就不再彈框了, 原因在於通過第7行解除了事件綁定, 因爲arguments.callee指向的是當前作用域下arguments對象所屬的函數, 此時是那個被綁定的匿名函數, 因此通過removeEventListener就可以解除匿名函數的綁定了!!

通過這兩個例子我們可以發現arguments.callee可以做到平常在正常情況下做不到的事情, 所以這個屬性我覺得還挺有用的.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章