js函数柯里化的理解

Posted vcxiaohan2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js函数柯里化的理解相关的知识,希望对你有一定的参考价值。

函数柯里化理解示例

// 求和
let add = function (a, b, c) 
  return a + b + c



  /* 简单版curry函数示例 */

  // 对求和函数做curry化
  let f1 = curry(add, 1, 2, 3)
  console.log('简单版', f1())// 6

  // 对求和函数做curry化
  let f2 = curry(add, 1, 2)
  console.log('简单版', f2(3))// 6

  // 对求和函数做curry化
  let f3 = curry(add)
  console.log('简单版', f3(1, 2, 3))// 6

  // 但是简单版curry函数多次调用会报错,如下:
  // console.log('简单版',f3(1)(2)(3))// Uncaught TypeError: f3(...) is not a function

  // 简单版(只能调用1次)
  function curry(fn) 
    // 缓存除函数fn之外的所有参数
    let args = Array.prototype.slice.call(arguments, 1)
    // 闭包
    return function () 
      // 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
      let newArgs = args.concat(Array.from(arguments))
      // 调用,这里的apply只是为了方便传参数,可以不用
      return fn.apply(null, newArgs)
    
  



  /* 复杂版curry函数示例 */

  // 对求和函数做curry化
  let f1 = curry(add, 1, 2, 3)
  console.log('复杂版', f1())// 6

  // 对求和函数做curry化
  let f2 = curry(add, 1, 2)
  console.log('复杂版', f2(3))// 6

  // 对求和函数做curry化
  let f3 = curry(add)
  console.log('复杂版', f3(1, 2, 3))// 6

  // 复杂版curry函数可以多次调用,如下:
  console.log('复杂版', f3(1)(2)(3))// 6
  console.log('复杂版', f3(1, 2)(3))// 6
  console.log('复杂版', f3(1)(2, 3))// 6

  // 复杂版(每次可传入不定数量的参数,当所传参数总数不少于函数的形参总数时,才会执行)
  function curry(fn) 
    // 闭包
    // 缓存除函数fn之外的所有参数
    let args = Array.prototype.slice.call(arguments, 1)
    return function () 
      // 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
      let newArgs = args.concat(Array.from(arguments))
      if (newArgs.length < fn.length) // 累积的参数总数少于fn形参总数
        // 递归传入fn和已累积的参数,这里的call只是为了方便传参数,可以不用
        return curry.call(null, fn, ...newArgs)
       else 
        // 调用,这里的apply只是为了方便传参数,可以不用
        return fn.apply(null, newArgs)
      
    
  

参数解构版本:


function curry(fn, ...args) 
  return function(...newArgs) 
    let allArgs = args.concat(newArgs)

    if(allArgs.length<fn.length) 
      return curry(fn, ...allArgs)
    else 
      return fn(...allArgs)
    
  

前端开发者进阶之函数柯里化Currying
JavaScript专题之函数柯里化

js bind函数理解示例(使用了柯里化)

// 全局变量
a = 1

// 求和
let add = function (b, c) 
  return this.a + b + c



  /* 作为普通函数直接调用 */
  // 此时this指向window,window.a是1
  console.log(add(2, 3))// 6



  /* 简单版bind实现,不具备curry化效果(不支持在传入对象的同时传入其他参数) */
  Function.prototype.bind = function (obj) 
    // 缓存Function构造函数的this(表达式函数声明时相当于new Function...)
    const self = this
    // 闭包
    return function () 
      // 调用
      return self.apply(obj, arguments)
    
  

  let f1 = add.bind( a: 0 )
  console.log(f1(2, 3))// 5

  // 但是简单版bind实现不支持对象和其他参数同时传入,如下:
  let f2 = add.bind( a: 0 , 2, 3)
  // 因为上一行代码传入的2、3并没有接收到,所以求和后返回NaN
  console.log(f2())// NaN



  /* 复杂版bind实现,具备部分curry化效果(之所以说部分,是因为它支持在传入对象的同时可以其他参数,但是不支持多次调用) */
  Function.prototype.bind = function (obj) 
    // 缓存Function构造函数的this(表达式函数声明时相当于new Function...)
    const self = this
    // 缓存除函数fn之外的所有参数
    let args = Array.prototype.slice.call(arguments, 1)
    // 闭包
    return function () 
      // 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
      let newArgs = args.concat(Array.from(arguments))
      // 调用
      return self.apply(obj, newArgs)
    
  

  let f1 = add.bind( a: 0 )
  console.log(f1(2, 3))// 5

  // 复杂版bind实现支持对象和其他参数同时传入,如下:
  let f2 = add.bind( a: 0 , 2, 3)
  console.log(f2())// 5

  // 但是复杂版bind实现多次调用会报错,如下:
  let f3 = add.bind( a: 0 )
  // console.log(f3(2)(3))// Uncaught TypeError: f3(...) is not a function

JS bind() 方法之人和狗的故事
JS中的bind的实现以及使用

装饰者模式理解示例(使用了柯里化)

大家看以下代码,是不是思路都是想通的,详细的大家就自行拓展吧

// 在之前执行
Function.prototype.before = function (fn) 
  let self = this
  return function () 
    fn.apply(this, arguments)
    return self.apply(this, arguments)
  

// 在之后执行
Function.prototype.after = function (fn) 
  let self = this
  return function () 
    let res = self.apply(this, arguments)
    fn.apply(this, arguments)
    return res
  

function foo(params) 
  console.log(params, 1)
  return 22

// 钩子可以共享参数和返回值
console.log(foo.before((params) => 
  console.log(params, 2)
).after((params) => 
  console.log(params, 3)
)( a: 1 ))

以上是关于js函数柯里化的理解的主要内容,如果未能解决你的问题,请参考以下文章

js - 理解函数柯里化

js - 理解函数柯里化

函数柯里化的理解

柯里化的一点小理解

人类高质量JS函数柯里化

人类高质量JS函数柯里化