zhentonglee / blog

记录成长过程,构建系统的知识体系。
0 stars 0 forks source link

js函数柯里化 #15

Open zhentonglee opened 4 years ago

zhentonglee commented 4 years ago

维基百科上说道:柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。概念有点难理解,先看以下例子:

// 普通的add函数
function add(x, y) {
    return x + y;
}
// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y;
    }
}
add(1, 2)                 // 3
curryingAdd(1)(2)   // 3

函数柯里化的好处?

  1. 参数复用
    
    // 正常正则验证字符串 reg.test(txt)

// 函数封装后 function check(reg, txt) { return reg.test(txt) } check(/\d+/g, 'test') //false check(/[a-z]+/g, 'test') //true // Currying后 function curryingCheck(reg) { return function(txt) { return reg.test(txt) } } let hasNumber = curryingCheck(/\d+/g) let hasLetter = curryingCheck(/[a-z]+/g) hasNumber('test1') // true hasNumber('testtest') // false hasLetter('21212') // false

2. 提前确认

let on = function(element, event, handler) { if (document.addEventListener) { if (element && event && handler) { element.addEventListener(event, handler, false); } } else { if (element && event && handler) { element.attachEvent('on' + event, handler); } } } // 函数自执行后返回一个新的函数,也就提前确定了 let on = (function() { if (document.addEventListener) { return function(element, event, handler) { if (element && event && handler) { element.addEventListener(event, handler, false); } }; } else { return function(element, event, handler) { if (element && event && handler) { element.attachEvent('on' + event, handler); } }; } })();

3. 延迟运行

Function.prototype.bind = function (context) { let _this = this let args = Array.prototype.slice.call(arguments, 1) return function() { return _this.apply(context, args) } }

#### 通用的封装方法

function currying(fn, ...args){ //fn.length是函数参数的个数 if(fn.length <= args.length){ return fn(...args); } return function(...argsX){ return currying(fn, ...args, ...argsX); } } function add(a,b,c){ return a + b + c; } let curryingAdd = currying(add); curryingAdd(1)(2)(3);

扩展

// 实现一个add方法,使计算结果能够满足如下预期: add(1)(2)(3) = 6; add(1, 2, 3)(4) = 10; add(1)(2)(3)(4)(5) = 15;

function add() { // 第一次执行时,定义一个数组专门用来存储所有的参数 let _args = Array.prototype.slice.call(arguments); // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值 let _adder = function() { // 第二次及以上执行,不断返回该函数 _args.push(...arguments); return _adder; }; // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回 _adder.toString = function () { return _args.reduce(function (a, b) { return a + b; }); } // 第一次执行返回 return _adder; }

zhentonglee commented 2 years ago
const curry = (func, ...args) => {
  const fnLen = func.length

  return function (...innerArgs) {
    innerArgs = args.concat(innerArgs)

    if (innerArgs.length < fnLen) {
      return curry(func, ...innerArgs)
    } else {
      func.apply(this, innerArgs)
    }
  }
}