柯里化 与 反柯里化

190 阅读1分钟

1. currying 函数柯里化

1.1 什么是柯里化

将多个参数的函数,提取成接收更少参数的函数,即:提前接收部分参数,延迟执行,不立即输出结果,而是返回一个接收剩余参数的函数。

1.2 怎样实现

currying(add)(1)(2, 3)(4)(5)(6);

currying(add)(1)(2, 3)(4)(5)(6)( );

code

const currying = (fn, arr = []) => {
  let originLength = fn.length;
  return (...args) => {
    arr = [ ...arr, ...args];
    let currentLength = arr.length;
    // 如果 原始函数需传入参数个数 > 返回的所有函数 参数总量
    return originLength > currentLength ?
      // 参数不够 继续递归 返回函数
      currying(fn, arr) :
      // 否则 返回函数调用  或者 回调函数 内包裹函数调用
      // fn(...arr);
      () => fn(...arr);
  }
}

test

function add(a, b, c, d, e, f) {
  let arr = Array.from(arguments),
      sum = arr.reduce((sum, n) => sum + n, 0);
  console.log(sum)
}
// 返回 函数调用方式
currying(add)(1)(2, 3)(4)(5)(6);   // 21
// 返回 回调函数
currying(add)(1)(2, 3)(4)(5)(6)();  // 21

运用类型校验

批量产生 校验函数

const checkType = type => content => Object.prototype.toString.call(content) === `[object ${type}]`;

let types = [ "String", "Number", "Boolean", "undefined", "null", "function", "Object", "Array", "Symbol" ];

let utils = {};

types.forEach(type => utils[`is${type}`] = checkType(type));

utils.isString(""); // true
utils.isSymbol(Symbol()); // true

2. uncurrying 反柯里化

2.1 什么是反柯里化

将对象下的方法,提取出,可被其他对象使用。

2.2 怎样实现

toString("string");

方法(一)

// code
// const uncurrying = fn => (...args) => fn.call(...args);
const uncurring = fn => (context, ...args) => Reflect.apply(fn, context, args);
// or
const uncurring = fn => (context, ...args) => Function.prototype.apply.call(fn, context, args);

// test 1
let toString = uncurrying(Object.prototype.toString);
toString("string");
// "[object String]"

// test 2
let tom = { 
  name: "Tom",
  introduce() {
    console.log(`My name is ${this.name}.`);
  }
}

let jerry = {
  name: "Jerry",
}

uncurrying(tom.introduce)(jerry);
// My name is Jerry.

方法(二)

// code
// ES5
Function.prototype.uncurrying = function () {
  let that = this;
  return function () {
    let arr = Array.prototype.slice.call(arguments);
    return that.call(arr[0]);
  }
}
// ES6
Reflect.defineProperty(Function.prototype, "uncurrying", {
  value: function (fn) {
    return (...args) => this.call(...args);
  }
})

// test 1
let toString = Object.prototype.toString.uncurrying();
toString([]);
// "[object Array]"

// test 2
let tom = { 
  name: "Tom",
  introduce() {
    console.log(`My name is ${this.name}.`);
  }
}

let jerry = {
  name: "Jerry",
}

let introduce = tom.introduce.uncurrying();
introduce(jerry);
// My name is Jerry.