个人杂谈1-Ramda的核心函数curryN和占位符思想

103 阅读2分钟

首先先安利一波,ramda.js是一个简洁优秀的函数式工具库

接着要介绍一下柯里化(currying),就是通过函数作用域(闭包),返回新函数,达到依次减少参数的一个编程技法

可能大家会说那lodash我用的也很好,lodash很优秀,但是函数是一等公民这点ramda做的更好(这点仁者见仁,我觉得函数优先,是更优秀的实践方式,我本人认可喜欢)

区别

  1. lodash的工具函数第一个参数是数据(data),第二个参数是fn(业务函数),理念上ramda秉承的是函数优先的理念
  2. ramda的所有函数都是经过currying包装的,使用起来更有函数优先的味道
// 比如ramda里面的add函数
R.add(1)(2) // 3
const addOne = add(1)
addOne(2) // 3

// 下面展示一个前些年面试上屡见不鲜的面试题
实现下面这个add函数
add(1)(2)(3) // 6
// 1. 首先三个参数
const add$1 = (a, b, c) => a + b + c
// 2. 进行了3次函数执行,说明每次返回新的函数
// 这个题考验的就是柯里化,我们尝试写一个
// 第一个要知道需要几个参数,还有业务函数,还需要一个缓存上次参数的容器,返回一个被包装过的函数,支持柯里化
const curryN$1 = (fn, length, cache) => {
    return (...args) => {
        // cache是上次函数执行缓存的参数
        // args是本次执行函数带来的参数
        const params = [...cache, ...args]
        if (params.length >= length) {
            return fn.apply(null, params)
        }
        return curryN$1(fn, length, params)
    }
}
// 成功了但是有点问题,作为一个包装函数 包装时cache不用手动输入
const curryN = (fn, length) => {
    return curryN$1(fn, length, [])
}
// OK 基本完成 
// ramda的实现更为巧妙curryN本身也是一个柯里化函数
  1. 占位符
// 占位符一般情况确实用的不多,但是提供了一种新的解决方法
const add$1 = (a, b, c) => a + b + c
const add = R.curryN(3, add$1)
add(R.__, 1, 2)(3) // 假设有历史遗留问题,可以这么去做其实就是加了一层中间层去处理参数
// 咱们只做简单模拟
const placeholder = Symbol('fn_placeholder')
const curryN$1 = (fn, length, cache) => {
    return (...args) => {
        // cache是上次函数执行缓存的参数
        // args是本次执行函数带来的参数
        const args$1 = args.filter((param) => {
        return param !== placeholder
        })
        const params = [...cache, ...args$1]
        if (params.length >= length) {
            return fn.apply(null, params)
        }
        return curryN$1(fn, length, params)
    }
}

const add = curryN$1(add)
add(placeholder, placeholder, 1, 2)(placeholder, 3)
// OK 基本完成 

我能力尚浅,我觉得ramda的核心就于此,有不同的想法,大家也可以一起思考