Skip to content

JavaScript中的不完全函数调用

jnotnull edited this page Jul 16, 2014 · 15 revisions

除非你使用另一种函数式编程语言,比如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中,函数也是一个类,正因为如此,函数可以接受函数作为参数,也能够返回函数。必要和类函数经常一起配合,返回函数作为参数继续进行运算。

While this example offers the convenience of allowing you to call addOne(2) instead of add(1, 2), it doesn’t come without a price. First, the actual adding logic is duplicated in both the more generic add function and makeAdder factory function, which can be problematic since the code is no longer as DRY as it could be. Second, for every different something function you want to handle in this manner, you’d need to manually create a makeSomething factory function.

Clone this wiki locally