JavaScript是函数式编程语言吗?
没有神奇的公式能够判定一种语言是不是“函数式”语言。有些语言很明显就是函数式的,就像另外一些语言很明显不是函数式的,但是有大量语言的是模棱两可的中间派。
于是这里给出一些常用的、重要的函数式语言的“配料”(JavaScript能实现用粗体标志)
- 函数是“第一等公民”
- 函数能够返回函数
- 词法上支持闭包
- 函数要“纯粹”
- 可靠递归
- 没有变异状态
这决不是一个排它的列表,但是我们至少要逐个讨论Javascript中最重要的三个特性,它们支撑我们可以用函数式的方式来编写程序。
让我们逐个详细的了解下:
函数是“第一等公民”
这条可能是在所有的配料中最明显的,并且可能是在很多现代编程语言中最常见到的。
在JavaScript局部变量是通过var关键字来定义的。
1 2 |
; html-script: false ] var foo = "bar"; |
JavaScript中把函数以局部变量的方式定义是非常容易做到的。
1 2 3 |
; html-script: false ] var add = function (a, b) { return a + b; }; var even = function (a) { return a % 2 === 0; }; |
这些都是事实,变量:变量add和变量even通过被赋值的方式,与函数定义建立引用关系,这种引用关系是在任何时候如果需要是可以被改变的。
1 2 3 4 5 6 |
; html-script: false ] // capture the old version of the function var old_even = even; // assign variable `even` to a new, different function even = function (a) { return a & 1 === 0; }; |
当然,这没有什么特别的。但是成为“第一等公民”这个重要的特性使得我们能够把函数以参数的方式传递给另一个函数。举个例子:
1 2 |
; html-script: false ] var binaryCall = function (f, a, b) { return f(a, b); }; |
这是一个函数,他接受了一个二元函数f,和两个参数a,b,然后调用这个二元函数f,该二元函数f以a、b为输入参数。
1 2 |
; html-script: false ] add(1,2) === binaryCall(add, 1, 2); // true |
这样做看起来有点笨拙,但是当把接下来的函数式编程“配料”合并考虑的时候,牛叉之处就显而易见了…
函数能返回函数(换个说法“高阶函数”)
事情开始变的酷起来。尽管开始比较简单。函数最终以新的函数作为返回值。举个例子:
1 2 3 4 |
; html-script: false ] var applyFirst = function (f, a) { return function (b) { return f(a, b); }; }; |
这个函数(applyFirst)接受一个二元函数作为其中一个参数,可以把第一个参数(即二元函数)看作是这个applyFirst函数的“部分操作”,然后返回一个一元(一个参数)函数,该一元函数被调用的时候返回外部函数的第一个参数(f)的二元函数f(a, b)。返回两个参数的二元函数。
让我们再谈谈一些函数,例如mult(乘法)函数:
1 2 |
; html-script: false ] var mult = function(a, b) { return a * b; }; |
依循mult(乘法)函数的逻辑,我们可以写一个新的函数double(乘方):
JavaScript是函数式编程语言吗?
没有神奇的公式能够判定一种语言是不是“函数式”语言。有些语言很明显就是函数式的,就像另外一些语言很明显不是函数式的,但是有大量语言的是模棱两可的中间派。
于是这里给出一些常用的、重要的函数式语言的“配料”(JavaScript能实现用粗体标志)
- 函数是“第一等公民”
- 函数能够返回函数
- 词法上支持闭包
- 函数要“纯粹”
- 可靠递归
- 没有变异状态
这决不是一个排它的列表,但是我们至少要逐个讨论Javascript中最重要的三个特性,它们支撑我们可以用函数式的方式来编写程序。
让我们逐个详细的了解下:
函数是“第一等公民”
这条可能是在所有的配料中最明显的,并且可能是在很多现代编程语言中最常见到的。
在JavaScript局部变量是通过var关键字来定义的。
1 2 |
; html-script: false ] var foo = "bar"; |
JavaScript中把函数以局部变量的方式定义是非常容易做到的。
1 2 3 |
; html-script: false ] var add = function (a, b) { return a + b; }; var even = function (a) { return a % 2 === 0; }; |
这些都是事实,变量:变量add和变量even通过被赋值的方式,与函数定义建立引用关系,这种引用关系是在任何时候如果需要是可以被改变的。
1 2 3 4 5 6 |
; html-script: false ] // capture the old version of the function var old_even = even; // assign variable `even` to a new, different function even = function (a) { return a & 1 === 0; }; |
当然,这没有什么特别的。但是成为“第一等公民”这个重要的特性使得我们能够把函数以参数的方式传递给另一个函数。举个例子:
1 2 |
; html-script: false ] var binaryCall = function (f, a, b) { return f(a, b); }; |
这是一个函数,他接受了一个二元函数f,和两个参数a,b,然后调用这个二元函数f,该二元函数f以a、b为输入参数。
1 2 |
; html-script: false ] add(1,2) === binaryCall(add, 1, 2); // true |
这样做看起来有点笨拙,但是当把接下来的函数式编程“配料”合并考虑的时候,牛叉之处就显而易见了…
函数能返回函数(换个说法“高阶函数”)
事情开始变的酷起来。尽管开始比较简单。函数最终以新的函数作为返回值。举个例子:
1 2 3 4 |
; html-script: false ] var applyFirst = function (f, a) { return function (b) { return f(a, b); }; }; |
这个函数(applyFirst)接受一个二元函数作为其中一个参数,可以把第一个参数(即二元函数)看作是这个applyFirst函数的“部分操作”,然后返回一个一元(一个参数)函数,该一元函数被调用的时候返回外部函数的第一个参数(f)的二元函数f(a, b)。返回两个参数的二元函数。
让我们再谈谈一些函数,例如mult(乘法)函数:
1 2 |
; html-script: false ] var mult = function(a, b) { return a * b; }; |
依循mult(乘法)函数的逻辑,我们可以写一个新的函数double(乘方):