三行代码实现 JS 柯里化

栏目: 编程工具 · 发布时间: 7年前

内容简介:最近有看到一些柯里化的文章,怎么说呢,感觉很奇怪。一篇是阿里云的译文,文章末尾给出了这样一个 "curry":作者前面明明例举了柯里化和部分应用的区别,结果最后说我们实现下柯里化吧,然后写了个部分应用……太假了,我忍不住评论了一下:然后今天看到我们组欢哥的文章,说实话看了一下开头这段代码我就不太有耐心看下面具体的分析了:

最近有看到一些柯里化的文章,怎么说呢,感觉很奇怪。一篇是阿里云的译文,文章末尾给出了这样一个 "curry":

function curry(fn, ...args) {
    return (..._arg) => {
        return fn(...args, ..._arg);
    }
}
复制代码

作者前面明明例举了柯里化和部分应用的区别,结果最后说我们实现下柯里化吧,然后写了个部分应用……太假了,我忍不住评论了一下:

三行代码实现 JS 柯里化

然后今天看到我们组欢哥的文章,说实话看了一下开头这段代码我就不太有耐心看下面具体的分析了:

// 定义占位符
var _ = '_';

function magician3 (targetfn, ...preset) {
  var numOfArgs = targetfn.length;
  var nextPos = 0; // 下一个有效输入位置的索引,可以是'_',也可以是preset的结尾

  // 查看是否有足够的有效参数
  if (preset.filter(arg=> arg !== _).length === numOfArgs) {
    return targetfn.apply(null, preset);
  } else {
    // 返回'helper'函数
    return function (...added) {
      // 循环并将added参数添加到preset参数
      while(added.length > 0) {
        var a = added.shift();
        // 获取下一个占位符的位置,可以是'_'也可以是preset的末尾
        while (preset[nextPos] !== _ && nextPos < preset.length) {
          nextPos++
        }
        // 更新preset
        preset[nextPos] = a;
        nextPos++;
      }
      // 绑定更新后的preset
      return magician3.call(null, targetfn, ...preset);
    }
  }
}
复制代码

这是在干嘛……然后欢哥他们发现了这段代码有 bug,分析了一通,解决了 bug,美好的青春啊朋友们,出去喝酒蹦迪大保健不好么,非得这么挥霍生命么……

在我们自己实现之前,对柯里化没什么概念的同学可以看下wiki(要看英文 wiki,中文 wiki 对柯里化的解释写得又乱又不准确,容易和部分应用混淆),简单来说柯里化就是把一个多参函数转换成接受单参的一系列函数。它跟部分应用的概念不太一样,部分应用是把一个多参函数“切”一刀,而柯里化是把函数“切”好多刀,直到中间每个函数都是单参的,最后得到的结果就是所谓的柯里化函数(curried function)。在 JS 里要手写个 curried function 其实就是手写个高阶函数,没什么特别的。那要实现一个通用的 curry,该怎么做呢,我不是针对谁,我是说上面那两个实现都在卖萌……

const curry = (fn) => {
    if (fn.length <= 1) return fn;

    const generator = (args, rest) => (!rest ? fn(...args) : arg => generator([...args, arg], rest - 1));

    return generator([], fn.length);
};
复制代码

这不就三行代码搞定了么(不算函数声明),测一下:

const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add); // 6

const log = (a, b, c) => {
    console.log(a, b, c);
};
const curriedLog = curry(log);
curriedLog('a')('b')('c'); // a b c
复制代码

好像没啥问题吧……emmmmm……欢迎打脸。

由此可见,在折腾什么 curry 什么 partial application 之前,还是多琢磨琢磨递归这种基本概念,顺便附送一个 FP Style 的快排吧,感受一下,突然感觉我也挺挥霍青春的……

const quickSort = (list) => {
    if (!list || !list.length) return [];
    if (list.length === 1) return list;

    const [middle, ...rest] = list;
    const reducer = (acc, x) => (
        x <= middle ? 
        { ...acc, left: [...acc.left, x] } : 
        { ...acc, right: [...acc.right, x] }
    );
    const { left, right } = rest.reduce(reducer, { left: [], right: [] });
    return [...quickSort(left), middle, ...quickSort(right)];
};

const list = [2, 3, 1, 8, 8, 1, 2, 18, 6, 2333];
const sorted = quickSort(list); // [ 1, 1, 2, 2, 3, 6, 8, 8, 18, 2333 ]

复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

React

React

卓越开发者联盟 / 寸志、范洪春、杨森、陈涌 / 电子工业出版社 / 2015-5-1 / CNY 65.00

2014 年横空出世的由Facebook 推出的开源框架React.js,基于Virtual DOM 重新定义了用户界面的开发方式,彻底革新了大家对前端框架的认识,将PHP 风格的开发方式迁移到客户端应用开发。其优势在于可以与各种类库、框架搭配使用。《React:引领未来的用户界面开发框架》是这一领域的首作,由多位一线专家精心撰写,采用一个全程实例全面介绍和剖析了ReactReact.js 的方方......一起来看看 《React》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换