Day21 函数反柯里化

109 阅读2分钟

每日一句

Age wrinkles the body, Quitting wrinkles the soul.

释义:岁月使皮肤起皱,放弃使灵魂起皱。

函数反柯里化

简介

函数柯里化:是一个多参的函数,我们可以先固定部分参数,返回一个可以接收剩余参数的函数,无形之间缩小了函数的适用范围。

函数反柯里化:字面上理解,功能跟柯里化相反,扩大适用范围,创建一个应用范围更广的函数。

反柯里化Uncurrying的话题来自JavaScript之父 Brendan Eich在2011年发表的一篇推特,它解决的问题是让对象去借用一个原本不属于自己的方法

代码理解方式:对象.某函数(参数1, 参数2)转成某函数(对象, 参数1, 参数2)

代码实现方式

通用方式

Function的原型上添加uncrurring方法,在执行时把uncrurring方法保存到self上;

借用apply把要借用的函数作为this环境赋给call,并传入之后的参数执行。

Function.prototype.uncrurring = function() {
  const self = this
  return (...args) => {
    return Function.prototype.call.apply(self, ...args)
  }
}

bind方式

Function.prototype.uncrurring = function(fn) {
  return fn.call.bind(this)
}

自定义函数

function uncrurring(fn) {
  return (obj, ...args) => {
    return fn.apply(obj, args)
  }
}

使用场景

  • 示例1: 简单文字替换
Function.prototype.unCurrying = function() {
  const self = this
  return function(...args) {   
    return Function.prototype.call.apply(self, args)
  }
}
const call = replaceTxt.unCurrying()

const Man = {
  ability: ['唱歌', '跳舞']
}
function replaceTxt(...args) {
  args.forEach(item => {
    if (this.ability.includes(item)) {
      console.log(`🤣:我会${item}.`)
      console.log(`🦜:我会${item}.`)
    } else {
      console.log(`🤣:我会${item}.`)
      console.log('🦜:你放P!')
    }
  })
}
~function(...args) {
  call(Man, ...args)
}('唱歌', '跳舞', '飞!')

// 输出结果:
🤣:我会唱歌.
🦜:我会唱歌.
🤣:我会跳舞.
🦜:我会跳舞.
🤣:我会飞!.
🦜:你放P!
  • 示例2:对象也能用push
let Person = {
  name: 'zhangsan'
}

const pushObj = Array.prototype.push.unCurrying()

pushObj(Person, {age: 30}, {eat: () => console.log('我吃鱼!')})

console.log(Person)
/* {
  '0': { age: 30 },
  '1': { eat: [Function: eat] },
  name: 'zhangsan',
  length: 2
} */
  • 示例3: 自己也可以借用

本身也是一个方法

const unCurrying = Function.prototype.unCurrying.unCurrying()
const Map = unCurrying(Array.prototype.map)
const Obj = { 0: '王小二', 1: '张小明', 2: '捣蛋鬼', length: 3 }

console.log(Map(Obj, n => n + '真棒!'))
// [ '王小二真棒!', '张小明真棒!', '捣蛋鬼真棒!' ]