2-5 函數返回函數與Currying

前面的cps範例裡面,使用了函數返回函數,這是為了把cps callback傳遞給onreadystatechange事件處理函數的方法。(因為這個事件處理函數並沒有設計好會傳送/接收這樣的參數)實際會執行的事件處理函數其實是內層返回的那個函數,之外包覆的這個函數,主要是為了利用Closure,把next傳給內層的事件處理函數。這個方法更常使用的地方,是為了解決一些scope問題。例如:

<script>
var accu=0,count=10;
for(var i=0; i<count; i++) {
  setTimeout(
    function(){
      count--;
      accu+=i;
      if(count<=0)
        console.log(accu)
    }
  , 50)
}
</script>

最後得出的結果會是100,而不是想像中的45,這是因為等到setTimeout指定的函數執行時,變數i已經變成10而離開迴圈了。要解決這個問題,就需要透過Closure來保存變數i:

<script>
var accu=0,count=10;
for(var i=0; i<count; i++) {
  setTimeout(
    function(i) {
     return function(){
    count--;
       accu+=i;
       if(count<=0)
         console.log(accu)
     };
   }(i)
  , 50)
}
//淺藍色底色的部份,是跟上面例子不一樣的地方
</script>

函數返回函數的另外一個用途,是可以暫緩函數執行。例如:

function add(m, n) {
  return m+n;
}
var a = add(20, 10);
console.log(a);

add這個函數,必須同時輸入兩個參數,才有辦法執行。如果我希望這個函數可以先給它一個參數,等一些處理過後再給一個參數,然後得到結果,就必須用函數返回函數的方式做修改:

function add(m) {
  return function(n) {
    return m+n;
  };
}
var wait_another_arg = add(20);//先給一個參數
var a = function(arr) {
  var ret=0;
  for(var i=0;i<arr.length;i++) ret+=arr[i];
  return ret;
}([1,2,3,4]);//計算一下另一個參數
var b = wait_another_arg(a);//然後再繼續執行
console.log(b);

像這樣利用函數返回函數,使得原本接受多個參數的函數,可以一次接受一個參數,直到參數接收完成才執行得到結果的方式,有一個學名就叫做...Currying

綜合以上許多奇技淫巧,就可以透過用函數來處理函數的方式,調整程式流程。接下來看看...


Comments