码迷,mamicode.com
首页 > 编程语言 > 详细

javascript里的偏函数——本质函数式编程+闭包,返回函数

时间:2016-11-25 19:54:31      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:完全   generator   tor   支持   ack   param   lex   柯里化   加法   

除非你已经使用过其他的函数式编程,不然你可能对下面这两个概念很陌生:“偏函数应用”和“函数柯里化“。

偏函数应用,英文是partial application,也可以译作“局部应用”、“部分应用”、“偏应用”
函数柯里化,英文是currying,也可以译作“局部套用”、“加里化”、“卡瑞化”

话虽如此,但是假如你一旦理解了这两个概念,你就完全可以在自己的代码里使用他们。

Functions

即使你已经很熟悉JavaScript的function, 知道function可以作为返回值,可以作为参数。
但是我还是推荐你读一下这个第一部分。如果不需要,也可以跳过,直接看局部应用的章节。

我们首先看一个非常基础的例子:

function add(a, b) {
  return a + b;
}

add(1, 2);    // 3
add(1, 3);    // 4
add(1, 10);   // 11
add(1, 9000); // 9001

尽管上面的例子是非常的简单,但是还是演示出了我们反复调用一个function的场景,并且每次传入的第一个参数都是相同的,在上面的代码里就是数字1

Functions返回Functions

我们也可以创建一个叫做makeAdder的function,这个function会返回另一个可以传入参数的function。(像这种可以用来创建其他function或object的function,一般会叫做工厂 - factories)

返回的函数,如果往里面传入参数调用,可以把传入的参数值和原来设的参数值,返回相加的结果。

// More general function.
function add(a, b) {
  return a + b;
}

add(1, 2);  // 3
add(10, 3); // 13

// More specific function generator.
function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}

// More specific functions.
var addOne = makeAdder(1);
addOne(2);  // 3
addOne(3);  // 4

var addTen = makeAdder(10);
addTen(2);  // 12
addTen(3);  // 13

上面的代码之所以可行,是因为JavaScript支持闭包的功能,由于闭包的存在,使得function可以访问到这个function外部的变量,甚至在调用这个function时的作用域的外层。

除此之外,在JavaScript里面,function是一等公民。正因为如此,function可以接受function作为参数,也可以返回function.

闭包和函数这个一等公名经常一起配合着工作:使得返回的function可以继续使用传入的参数。

上面的代码给我们提供了一些方便,我们可以不再使用add(1, 2),而直接使用addOne(2),但是实现这个并不是不需要付出代价的。

首先,实际做加法的逻辑在上面两个例子的代码中还是重复的,这样还是会有些问题。

其次,对每个类似于上面的加法场景,用这种方式去独立除不同的逻辑,我们将需要手工创建makeSomething的工厂function。

Functions接受Functions

下面的逻辑步骤是创建一个更普遍的工厂function,不仅接受一个要绑定的参数,也会接受一个function,这个function里面包含了所有的核心逻辑。(传入到其他function的function,一般被成为回调函数-callbacks)

用这种方式,一个单独的工厂function能够被用来创建function绑定。

注意,原始的function被没有被更新,并且他们的行为也不会改变。他们很容易被调用。

// Relatively flexible, more specific function generator.
function bindFirstArg(fn, a) {
  return function(b) {
    return fn(a, b);
  };
}

// More general functions.
function add(a, b) {
  return a + b;
}

add(1, 2);           // 3

function multiply(a, b) {
  return a * b;
}

multiply(10, 2);     // 20

// More specific functions.
var addOne = bindFirstArg(add, 1);
addOne(2);           // 3
addOne(3);           // 4
addOne(10);          // 11
addOne(9000);        // 9001

var multiplyByTen = bindFirstArg(multiply, 10);
multiplyByTen(2);    // 20
multiplyByTen(3);    // 30
multiplyByTen(10);   // 100
multiplyByTen(9000); // 90000

上面这段代码,亮点不在于它可以将某个参数绑定到任意的function,并且这个参数作为绑定的function的第一个参数,它还能将方法绑定它自己身上作为第一个参数,因此创建了一个可绑定的function

想想这种情况:假如bindFirstArg能够将第一个参数绑定到一个function,但是这个function可以接受两个参数,比如传进去1和10,1用来加,10用来乘。
bindFirstArg可以接受两个2参数,假如第一个参数是它自己,也就是bindFirstArg可以用来绑定它自己。

看下面的例子:

// More specific function generator.
var makeAdder = bindFirstArg(bindFirstArg, add);

// More specific functions.
var addOne = makeAdder(1);
addOne(2); // 3
addOne(3); // 4

var addTen = makeAdder(10);
addTen(2); // 12
addTen(3); // 13

 

javascript里的偏函数——本质函数式编程+闭包,返回函数

标签:完全   generator   tor   支持   ack   param   lex   柯里化   加法   

原文地址:http://www.cnblogs.com/bonelee/p/6102535.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!