coderliush / Blog

博客
0 stars 0 forks source link

JavaScript 之 柯里化和偏函数 #12

Open coderliush opened 3 years ago

coderliush commented 3 years ago

柯里化是什么

柯里化 是一种转换,将 f(a,b,c) 转换为可以被以 f(a)(b)(c) 的形式进行调用。参数数量满足,执行函数。参数数量不足,则返回偏函数。 柯里化不会调用函数。它只是对函数进行转换:let curried = curry(fn)

柯里化有什么用

固定不变的参数 举个例子,计算体积

function volume(l, w, h) {
    return l * w * h
}

在一组参数中,高度 h 都是固定的 100。另一组参数中,h 都是固定的 200

import { curry } from 'lodash'
let curriedFn = curry(volume)
let curried1 = curriedFn(100)
let curried2 = curriedFn(200)
curried1(2, 3)  // 600
curried2(1, 2)  // 400

柯里化怎么使用

柯里化接收一个参数:需要被柯里化的函数(如下文的 add).

import { curry } from 'lodash'
function add( fixed1, fixed2 ,x, y, z) {
    return x + y + z + fixed1 + fixed2
}
let curried = curry(add)
curried(1)(2)(3)  // 36
curried(1)(2, 3)  // 36
curried(1, 2, 3)  // 36
curried(1, 2)(3)  // 36

或者(伪代码):

let currided = curry(ajax)
$.post = curried(post)
$.get = curried(get)

实现一个柯里化函数

当传入的参数个数小于函数需要的参数个数时,闭包保存参数。 等于时,即达到函数需要的参数个数,此时执行函数。

// fn: curry 传入需要被柯里化的函数 
// arr: 是目前已经传入的所有参数合集. arr 不存在默认是空数组,存在就是添加过的参数合集
var curry = function curry (fn, argsList) {
  argsList = argsList || []
  // 柯里化返回一个函数 
  return function () {
    var args = [].slice.call(arguments)
    argsList = argsList.concat(args)
    // return 函数执行的结果 或者 return 一个函数
    return argsList.length >= fn.length 
      ? fn.apply(null, argsList)    
      : curry(fn, argsList)
    }
}
// es6
const curry = fn => (...args) => fn.bind(null, ...args) 

const curry = (fn, argsList = []) => (...args) => {
    argsList.length >= fn.legnth
        ? fn(...argsList)
        : curry(fn, argsList)
}

偏函数(部分应用)

fn('a', 'b', 'c') let partialed = partial(fn, 'a', 'b') partialed('c') 偏函数:接受一个函数 fn ,传入部分参数,返回一个接受剩余参数的新函数 partialed。 bind 就是一个偏函数

柯里化和偏函数的区别

柯里化:将 fn 转化为 x 个接收 1 个参数的函数。 柯里化后的函数可多次调用,直到参数个数满足。 偏函数:初始化传入参数,返回一个接收剩余参数的函数。partial 后只可调用一次。

偏函数的实现

function partial(fn) {
    var initArgs = [].slice.call(arguments, 1)
    return function () {
        var otherArgs = [].slice.call(arguments)
        return fn.apply(null, initArgs.concat(otherArgs))
    }
}