了解 JavaScript 函数式编程 - 柯里化

栏目: JavaScript · 发布时间: 6年前

内容简介:在这个多彩的世界,有些事物对与我们来说并不是非必须的,就像我们早已习惯存在但是又非必须的东西:互联网,移动手机,微波炉,电梯等等。当他们不存在的时候我们也能正常的快乐的生存下去,但是一旦拥有了以后他们的存在就变得不可或缺。就像我们的 curry 工具一样。

curry 就是咖喱一样美好的 工具 性的拌料让我们的函数更加的易用耦合性低。

curry 的概念很简单: 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数 。 你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。

var add = function(x) {
  return function(y) {
    return x + y;
  };
};

var increment = add(1);
var addTen = add(10);

increment(2);
// 3

addTen(2);
// 12
复制代码

curry 的重要性

在这个多彩的世界,有些事物对与我们来说并不是非必须的,就像我们早已习惯存在但是又非必须的东西:互联网,移动手机,微波炉,电梯等等。当他们不存在的时候我们也能正常的快乐的生存下去,但是一旦拥有了以后他们的存在就变得不可或缺。就像我们的 curry 工具一样。

  • 我们来创建一个普通的 curry ,for your enjoyment 吧。这里用到了 lodash 函数库,不熟悉的朋友可以看一下 lodash 的官网
var curry = require('lodash').curry;

var match = curry(function(what, str) {
  return str.match(what);
});

var replace = curry(function(what, replacement, str) {
  return str.replace(what, replacement);
});

var filter = curry(function(f, ary) {
  return ary.filter(f);
});

var map = curry(function(f, ary) {
  return ary.map(f);
});
复制代码

我在上面的代码中遵循的是一种简单,同时也非常重要的模式。即策略性地把要操作的数据(String, Array)放到最后一个参数里。到使用它们的时候你就明白这样做的原因是什么了。

  • 下面我们开始使用上面的代码,看看为什么会这么去处理我们的函数。
// 匹配空格
match(/\s+/g, "hello world");
// [ ' ' ]

match(/\s+/g)("hello world");
// [ ' ' ]

// 引出一个 hasSpace 的函数变量,暂存用
var hasSpaces = match(/\s+/g);
// function(x) { return x.match(/\s+/g) }

// 使用这个 hasSpace 去做一些相关的处理
hasSpaces("hello world");
// [ ' ' ]

hasSpaces("spaceless");
// null

// 现在我们知道了它的返回值,我们可以通过其他函数做进一步的处理。比如筛选出一个有空格的数组值
filter(hasSpaces, ["tori_spelling", "tori amos"]);
// ["tori amos"]

// 保存这个 findSpace 的函数变量
var findSpaces = filter(hasSpaces);
// function(xs) { return xs.filter(function(x) { return x.match(/\s+/g) }) }

// 轻松的使用吧
findSpaces(["tori_spelling", "tori amos"]);
// ["tori amos"]

var noVowels = replace(/[aeiou]/ig);
// function(replacement, x) { return x.replace(/[aeiou]/ig, replacement) }

var censored = noVowels("*");
// function(x) { return x.replace(/[aeiou]/ig, "*") }

censored("Chocolate Rain");
// 'Ch*c*l*t* R**n'
复制代码

==我们为甚要这么多繁琐的步骤,而不是一步到位?==

这里表明的是一种“预加载”函数的能力,通过传递一到两个参数调用函数,就能得到一个记住了这些参数的新函数。分解的使用的函数,让每个函数更具有一定的独立性,使用导出的时候,做到纯净无污染的传递。

扩展我们的 curry

curry 的用处非常广泛,就像在 hasSpacesfindSpacescensored 看到的那样,只需传给函数一些参数,就能得到一个新函数。

  • 下面我们用 map 包裹一下我们的函数
var getChildren = function(x) {
  return x.childNodes;
};

var allTheChildren = map(getChildren);
复制代码

只传给函数一部分参数这样的操作通常被称为局部调用(partial application),因为只需要内联调用能够大量减少样板文件代码(boilerplate code)。

当我们谈论纯函数的时候,我们说它们接受一个输入返回一个输出。curry 函数所做的正是这样:每传递一个参数调用函数,就返回一个新函数处理剩余的参数。这就是一个输入对应一个输出啊。

练习一下

  • 这里引用了 ramda,如果没有的话可以手动引入安装一下和引用。
    • npm install ramda
var _ = require('ramda');

// 练习 1(局部调用的使用)
//==============
// 通过局部调用(partial apply)移除所有参数

var words = function(str) {
  return split(' ', str);
};

// 练习 1a(组合使用函数)
//==============
// 使用 `map` 创建一个新的 `words` 函数,使之能够操作字符串数组

var sentences = undefined;


// 练习 2
//==============
// 通过局部调用(partial apply)移除所有参数

var filterQs = function(xs) {
  return filter(function(x){ return match(/q/i, x);  }, xs);
};


// 练习 3(柯里化~)
//==============
// 使用帮助函数 `_keepHighest` 重构 `max` 使之成为 curry 函数

// 无须改动:
var _keepHighest = function(x,y){ return x >= y ? x : y; };

// 重构这段代码:
var max = function(xs) {
  return reduce(function(acc, x){
    return _keepHighest(acc, x);
  }, -Infinity, xs);
};


// use curry 1:
// ============
// 包裹数组的 `slice` 函数使之成为 curry 函数
// //[1,2,3].slice(0, 2)
var slice = undefined;


// use curry 2:
// ============
// 借助 `slice` 定义一个 `take` curry 函数,该函数调用后可以取出字符串的前 n 个字符。
var take = undefined;
复制代码

这是上面的答案,先别急着看答案,让我们先思考一下 链接

总结

通过简单地传递几个参数,就能动态创建实用的新函数;而且还能带来一个额外好处,那就是保留了数学的函数定义,尽管参数不止一个。

参考


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

PHP for the World Wide Web, Second Edition (Visual QuickStart Gu

PHP for the World Wide Web, Second Edition (Visual QuickStart Gu

Larry Ullman / Peachpit Press / 2004-02-02 / USD 29.99

So you know HTML, even JavaScript, but the idea of learning an actual programming language like PHP terrifies you? Well, stop quaking and get going with this easy task-based guide! Aimed at beginning ......一起来看看 《PHP for the World Wide Web, Second Edition (Visual QuickStart Gu》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具