-
Notifications
You must be signed in to change notification settings - Fork 2
JavaScript中的不完全函数调用
除非你使用另一种函数式编程语言,比如ML或者Haskell,否则,你可能对不完全调用函数调用和柯里化函数并不熟悉。但是一旦你理解了这些概念,你就可以在自己的代码中使用它们了。
注:这篇文章之前发布在MSDN上,但是已经被大幅重写了。这个最新版本更加准确。
函数
如果你是新手,即使你已经明白了js方法如何返回方法,并且也了解了传递方法作为函数参数,我还是建议你阅读第一章节。如果你已经掌握了这些知识,那可以跳过这个章节直接去阅读不完全函数调用章节
现在让我们潜下心来看个非常简单的例子:
function add(a, b) {
return a + b;
}
add(1, 2); // 3
add(1, 3); // 4
add(1, 10); // 11
add(1, 9000); // 9001
这个例子很简单,设想一下,你必须重复的调用一个函数,传递的第一个参数又是一样的。因为不必要的重复传递是导致错误的主要因素,所以一个方法就是你把重复的常量提取出来放到一个变量中,然后再在进行调用。
function add(a, b) {
return a + b;
}
var value = 1;
add(value, 2); // 3
add(value, 3); // 4
add(value, 10); // 11
add(value, 9000); // 9001
如你所见,使用变量替换使得代码具有更强的可修改性,当然也就更加可维护了。但是,这个代码还是有一些不必要的重复。如果新增一个固定的取值能够被执行无数次,那将需要我们去创建一个具有内置行为的专门函数。
函数调用函数
无论你是自己写代码,还是提供API,如果创建一个针对通用功能的专有包装函数,将会非常有用的。它可以被传递给到函数中并被执行。
一个方法就是准对通用功能,手工定义一个更加专有的函数。这在javascript中非常容易,因为函数可以调用其他函数
// More general function.
function add(a, b) {
return a + b;
}
add(1, 2); // 3
add(10, 3); // 13
// More specific functions.
function addOne(b) {
return add(1, b);
}
addOne(2); // 3
addOne(3); // 4
function addTen(b) {
return add(10, b);
}
addTen(2); // 12
addTen(3); // 13
通过这种方式定义的专有函数非常容易和直观,如果你拥有太多这样的函数,那就需要维护一些额外的代码了。
函数返回函数
这里你可以看到函数makeAdder,当被以传递一个变量调用的时候,它返回了一个新的函数(函数生成其他函数或者对象一般被认为是工厂)。返回的函数会加上传递的参数到之前制定的函数参数值,得到最终的结果。
// 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
在JS中可以这么做,因为JS支持闭包。闭包允许函数访问外层变量,甚至是当前运行环境之外的变量。 同时在JS中,函数是一类公民(译者注:first-class是指函数能够被当成参数进行传递到函数中),正因为如此,函数可以接受函数作为参数,也能够返回函数。闭包和函数经常一起配合,返回函数作为参数继续进行运算。
这个例子提供了一个方便的渠道,使你直接调用addOne(2)而不是add(1, 2),但是这个不是没有代价的。首先,通用增加函数和makeAdder 工厂的实际加逻辑是重复的。这样的代码就不够DRY了。第二,通过这种方式处理的不同函数,你需要手工创建一个工厂。