JavaScript 系列之閉包(三)

這是我參與8月更文挑戰的第10天,活動詳情查看:8月更文挑戰前端

5、柯里化

柯里化(Currying)是把接受多個參數的函數轉變爲單一參數的函數,而且返回接受餘下的參數且返回結果的新函數的技術。面試

簡單來講:segmentfault

  1. 經過閉包管理
  2. 支持鏈式調用
  3. 每次運行返回一個 function

即:經過將多個參數換成一個參數,每次運行返回新函數的技術markdown

5.1 柯里化舉例

// 普通的 add 函數
function add (a, b) {
  return a + b;
}
add(1, 2);
複製代碼
// 柯里化函數
function curryingAdd (x) {
  return function(y) {
    return x + y;
  }
}
curryingAdd(x)(y);
複製代碼

5.2 柯里化好處

  1. 參數複用
  2. 提早確認
  3. 延遲運行
// 校驗數字
let numberReg = /[0-9]+/g;

// 校驗小寫字母
let stringReg = /[a-z]+/g;

// currying 後
function curryingCheck(reg) {
  return function(txt) {
    return reg.test(txt);
  }
}


let checkNumber = curryingCheck(numberReg);
let checkString = curryingCheck(stringReg);


console.log(checkNumber('13888888888')); // true
console.log(checkString('jsliang')); // true
複製代碼

5.3 柯里化實現 add(1)(2)(3)

// 實現一個 add 方法,使計算結果可以知足如下預期
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
複製代碼
function add () {
  const numberList = Array.from(arguments);

  // 進一步收集剩餘參數
  const calculate = function() {
    numberList.push(...arguments);
    return calculate;
  }

  // 利用 toString 隱式轉換,最後執行時進行轉換
  calculate.toString = function() {
    return numberList.reduce((a, b) => a + b, 0);
  }

  return calculate;
}

// 實現一個 add 方法,使計算結果可以知足如下預期
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2, 3)(4)); // 10;
console.log(add(1)(2)(3)(4)(5)); // 15;
console.log(add(1)(2)(3)(4)(5, 6, 7)); // 28
複製代碼

5.4 柯里化實現 compose(foo, bar, baz)('start')

function foo(...args) {
  console.log(args[0]);
  return 'foo';
}
function bar(...args) {
  console.log(args[0]);
  return 'bar';
}
function baz(...args) {
  console.log(args[0]);
  return 'baz';
}

function compose() {
  // 閉包元素 - 函數列表
  const list = Array.from(arguments);

  // 閉包元素 - 函數列表執行位置
  let index = -1;

  // 閉包元素 - 上一個函數的返回
  let prev = '';

  // 返回閉包函數
  const doNext = function() {
    index++; // 索引值累加
    // 一開始沒有上一個元素時,獲取第二個括號的值
    if (!prev) {
      prev = arguments[0];
    }
    // 設置前一個結果爲當前函數返回
    prev = list[index](prev);
    // 遞歸調用
    if (index < list.length - 1) {
      doNext(index + 1);
    }
  };

  // 第一次返回閉包函數
  return doNext;
}

compose(foo, bar, baz)('start');
複製代碼

相關好文

相關文章
相關標籤/搜索