JavaScript是一种函数式编程语言吗?

145

仅仅因为函数是一等对象,有闭包和高阶函数,JavaScript就应该被称为函数式编程语言吗?我认为它主要缺少的是纯函数,并且它不像其他函数式语言(比如lisp)那样“感觉”像函数式语言,虽然这不是不能成为函数式语言的好理由...


12
不行!那只是防止它成为一种纯函数式语言。ML(至少是现代方言)也是不纯的,但没有人敢说它们不是函数式的 ;) - user395760
4
有很多语言被普遍认为是函数式的,但并非纯函数式。我不认为这是必需的。如果你想这么严格,那么大多数所谓的面向对象编程语言也不是真正的面向对象。结果会导致约95%的语言都不属于任何范式。 - jalf
7
为什么这很重要呢?当我编写C ++代码时,我并不关心语言是否"是OOP"。我关心它是否具有某些OOP特性,并且具有一些函数式编程特性、许多命令式编程特性和大量通用编程特性。但它是否是OOP语言、FP语言或其他类型的语言并不重要。同样的,当我在JS中编写代码时,它是否是FP并不重要。重要的是它支持许多不错的FP特性。似乎这个问题问错了。 - jalf
3
@hvgotcodes: 那又怎么样呢?绝对没有规定说它不是。 我的经验法则是,如果您可以使用JavaScript编写函数式程序,则它是一种功能性语言。 由于JavaScript具有一级函数、闭包和lambda表达式,我相信您可以这样做,因此就我而言,JavaScript是一种函数式语言。 显然不是纯函数式的,但我们通常认为的大多数FP语言也不是(例如SML)。 所以,我认为你需要放松一下。 如果这让你眼睛抽搐,你需要看医生。 - jalf
3
@jalf,当然。我提出这个问题的动机是想知道我的同龄人和比我聪明的人们的看法。 - hvgotcodes
显示剩余5条评论
15个回答

188

重复我自己的答案来回答类似的问题:

关于函数式编程语言,还没有一个被广泛接受的定义。

如果您将函数式语言定义为支持一级函数和lambda的语言,则JavaScript *是*函数式语言。

如果您还考虑了诸如支持不可变性、代数数据类型、模式匹配、部分应用等因素,那么JavaScript *不是*函数式语言。


我鼓励您阅读以下相关博客文章(以及这些文章下面的评论):


1
Mozilla的JavaScript实现的后续版本(从1.7开始)具有以解构赋值形式的模式匹配功能:https://developer.mozilla.org/en/New_in_JavaScript_1.7#section_20 - jbeard4
JavaScript有部分应用参数的概念,因此我想知道你说它不支持这一点的说法是否不正确? - johnbakers
3
几乎每种编程语言都支持偏应用,包括C语言。不过,这里的“支持”有不同的定义。在JavaScript中也是如此。关键是该语言是否轻松地支持和将偏应用作为一等公民。在JavaScript中,它并不是。如果你想了解我所说的,可以看看OCaml或Haskell。 - missingfaktor
据我所知,JavaScript 支持不可变性。 - fka
@fka,你能详细说明一下你的意思吗? - missingfaktor
显示剩余2条评论

27

我认为它是一种多范式语言。

编辑:它是一种多范式语言,包含函数式结构。


是的,我同意这是一个混合体和几个不同的东西。 - Ashley Grenon
6
但这并没有回答它是否同样具有功能性的问题。多重范式意味着支持多种编程范式,其中是否包括函数式编程? - jalf

18

如果你将"函数式编程"这个术语扭曲到哲学讨论的程度,那么这个问题可能会再次成为争议。但是,那时你就陷入了像" C++ 真的是一种编程语言吗?"这样的无用问题。

更日常的回答是 "不是"

函数式编程意味着程序的概念化是作为函数的评估,而不是控制流。代码是函数的描述,并且没有固有的控制流概念。

JavaScript 具有控制流并且被概念化为命令式语言。从它的设计目标来看,它显然不是一种函数式语言。


1
设计目标?你是什么意思?据我所知,它的灵感来源之一是Scheme。我想说的是,很明显它的设计目标之一是支持函数式编程以及其他大量的编程范式。 - jalf
2
它支持函数式编程,就像C++一样,只要你自己编写适当的基础 - 就像你可以通过一些工作在Haskell中模拟命令式语法一样。然而,JavaScript的语法导致人们认为它是一个工作流程,而不是函数的评估。因此,我(或大多数函数式程序员)认为将术语“函数式”应用得太广泛了。 - shuhalo
@user411768:所以你的意思是一种语言是否是函数式的取决于其标准库的设计?我以前从未听说过这个定义。Java具有编写函数式风格所需的大多数工具(例如闭包和匿名函数),而C++(目前)没有。我认为这使得JS比C ++更加FP。语言不强制您以FP样式编程并不意味着它“不太功能”,对吗? - jalf
1
(i) 标准库是标准的一部分,就像语法特性一样,并强调某种惯用和概念风格。例如,“带有STL的C ++”与“具有类的C”非常不同。它产生了影响。(ii) JavaScript具有面向对象、一等公民函数等特性 - 这些特性与命令式/函数式二分法相当正交。然而,它既没有直接实现柯里化,也没有提供纯度,也从未打算这样做。(iii) 我对此的最后一句话,请参见帖子的第一段。 - shuhalo
4
“JavaScript和C++提供相同的函数式编程便利”这种说法是错误的。在JavaScript中,函数式编程非常简单直接,不需要像在C++中那样通过复杂的构造实现相同的功能。很多优秀的C++程序员也明确表示并不鼓励在C++中使用函数式编程,而在JavaScript中进行函数式编程的文章则很多。 - johnbakers

10

"函数式编程"这个词现在已经被过度使用,几乎毫无意义。它有两个主要含义:

  1. 具备头等函数的能力
    • JavaScript 就有这个能力!
  2. 基于λ演算中的函数,强调避免使用可变状态(通常使用函数参数来替代)
    • 通常情况下,JavaScript 并不具备这个能力!

根据您选择的含义,问题就可以得到答案了。


有没有一份源代码使用“函数式编程”来指代将函数作为一等公民的语言? - shuhalo
@user411768:实际上,另一个回答者链接了维基百科的文章,该文章使用了这个定义。http://en.wikipedia.org/wiki/Javascript — Joel Spolsky在他关于“函数式编程”好处的“你的编程语言能做到这一点吗?”的帖子中也暗示了这个定义。 - Chuck
你注意到,通常情况下,JavaScript并没有使用你提到的第二点,但这并不意味着没有程序员正在使用它,也不意味着该语言不支持这样的功能,因为它确实支持。 - johnbakers
@OpenLearner:嗯,是的,但Java和许多其他通常被认为是严格命令式的语言也是如此——你可以以函数式风格编写它们,但这不是语言的最佳实践。 - Chuck
...但是最新的JS将支持它。 - Erik Reppen

3

我认为函数式编程没有一个确切的定义,但是人们认为“函数式编程”的许多内容都可以用JavaScript完成。在这篇文章中有一个很好的简短例子。


2
对我来说,JavaScript既是命令式语言又是函数式语言,你可以选择任意一种方式来使用它,甚至(哎呀)两种方式兼而有之。或者你可以选择使用一种范式,从不触及另一种。这取决于你。就像你一样,我认为JavaScript不应该被称为函数式语言,因为它允许你在函数式编程范式中进进出出。也许如果它有某种类似的指示,限制你只能使用函数式编程范式,那么我认为会很有用。但总之,我认为它更像是一个带有一些函数式编程特性的命令式/过程式语言。

按照这种推理,F# 不能再被称为函数式的。 - Eric Mickelsen
1
根据维基百科的说法,F#正是我刚才所称的Javascript:“F#[...]是一种多范式编程语言[...]它包括函数式编程以及命令式面向对象编程学科。” - Brian Onn

2
我倾向于不把编程语言看作具有一种特定的范式,而是认为它们适合于某些范式。然而,仅仅因为它们适合某种范式,并不意味着您必须使用该范式。在C中编写面向对象程序,在ML中编写命令式程序是完全可能的。因为一种语言没有为某种范式而设计,所以不使用某种范式来解决问题只会人为地限制自己(当然,在确定特定解决方案是否是好的解决方案时,仍应考虑语言的限制)。

0

@petraszd 我稍微改写了你的代码,以获得一个“新”的for运算符:

   
   function ffor(a, b, f){
     function it(i){
       if(i > b)return
       f(i)
       it(i+1)
     }
     it(a)
   }

   print("----" + new Date()+"----")

   var funcs = []
   ffor(0, 9, function(i){
     funcs.push(function(){return i})
   })

   ffor(0, 9, function(i){
     print(funcs[i]())
   })

但是我知道这种方式在大循环中有缺点...

关于JS尾递归优化的相关问题

P.S. 发布在这里是因为在发布评论时有代码格式问题


0
首先,我们必须定义函数式编程。我将其定义为任何本地支持并优先使用类似Scheme、Racket、Haskell或Clojure等经典(或至少被广泛认可的)函数式语言所共享的编程风格的语言。
其他语言,如OCaml、Elixir和Scala,比JS具有更深入的函数式支持,但仍倾向于被视为多范式。"函数式程度"是一个谱系。
所有这些都非常容易引起无休止的争论和挑剔,但这个定义似乎足够坚实,可以证明JS不是一个严肃的函数式语言,也永远不会成为一个严肃的函数式语言,就像任何其他现代的、多范式的语言一样,都具有一流的函数。
让我们选择一个具体的特性。该语言应该执行尾调用优化,以便您可以在线性数据结构上本地编写递归函数。几乎所有主要的JS实现都未能提供这个我们从典型的“函数式”语言(按上述定义)期望的基本功能,并且在撰写本文时没有计划(有关详细信息,请参见JavaScript中的函数是否进行了尾调用优化?)。

让我们给予怀疑的态度,加入TCO,但JS仍然无法提供即使是微不足道的不可变性设计目标,这是你期望从“真正”的函数式语言中得到的。在语言中引入const花费了数十年的时间,所有对象默认都是可变的。

由于向后兼容性,这些问题实际上无法完全解决;在事后将已经建立的多范式语言转变为真正的函数式语言并不是真正可能的。

JS与Python、Perl、PHP或Ruby一样具有功能性,它们都在列表上提供map/filter/reduce操作,并支持一级函数或过程。一级函数的存在为编写以函数式编程风格的代码提供了足够的机会。加入trampolines和ramda.js,一眼看去可能会让人信服。

问题是一级函数是否足以使语言“函数式”。实际上,维基百科列出了所有前述的函数式语言,但是,该列表包括除C和Go之外的几乎所有流行的、现代的、通用的语言(包括至少一个明确标识为非函数式设计),因此我认为这个定义并没有提供太多区分价值。

0

Javascript有其局限性。它的编程方式取决于你如何去编写代码。如果我以面向对象的方式编写代码,那么它不就是面向对象的吗?所以,如果你只是以“函数式”的方式编写代码,那么它就是函数式的。我想这是一种多范式语言,所以仅仅称之为一种语言并不完全准确。


如果你足够努力,你可以用任何语言以任何风格进行编程。更有意义的是讨论语言被设计为何种范式,以及在多大程度上。JS并不像它的同时代语言Perl、PHP、Ruby、Python等一样被设计成函数式语言。它是一种多范式语言,具有一些函数式特性,尤其是一级函数。我认为这还不足以称之为“函数式”语言,就像会游泳并不代表什么都是鱼一样。 - ggorlen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接