引言
JavaScript是一种强大的,却被误解的编程语言。一些人喜欢说它是一个面向对象的编程语言,或者它是一个函数式编程语言。另外一些人喜欢说,它不是一个面向对象的编程语言,或者它不是一个函数式编程语言。还有人认为它兼具面向对象语言和函数式语言的特点,或者,认为它既不是面向对象的也不是函数式的,好吧,让我们先搁置那些争论。
让我们假设我们共有这样的一个使命:在JavaScript语言所允许的范围内,尽可能多的使用函数式编程的原则来编写程序。
本系列文章就是要让你和我一起完成这样的旅程。首先,我们需要清理下脑子里那些关于函数式编程的错误观念。
在JS界被(重度)误解的函数式编程
显然有相当一批开发者一天到晚的以函数式范式的方式使用JavaScript。我还是要说有更大量的JavaScript开发者,并不真正理解那佯做的真正意义。
我确信,导致这种局面是因为很多用于服务端的web开发语言都源自C语言,而C语言,很显然不是一种函数式编程语言。
似乎有两个层级的混乱,第一个层级的混乱我们用下面这个在jQuery中经常会用到的例子来说明:
1 2 3 4 |
$(".signup").click(function(event){ $("#signupModal").show(); event.preventDefault(); }); |
嘿,仔细看。我传递一个匿名函数作为参数,这在JavaScript世界里被称作众所周知“CallBack”(回调)函数。
真有人会认为这就是函数式编程吗?根本不是!
这个例子展示了一个函数式语言的关键特性:函数作为参数。另一方面,这个3行代码的例子也违背了几乎所有其他的函数式编程范式。
第二个层级的混乱有点微妙。读到这里,一些追求潮流的JS开发者在暗自思考。
好吧,废话!但是我已经知道了所有关于函数式编程的知识与技能。我在我所有的项目上使用Underscore.js。
Underscore.js 是一个广受欢迎的JavaScript库,到处都在使用。举个例子,我有一组单词,我需要获得一个集合,集合里的每个元素是各个单词的头两个字母。用Underscore.js实现这个相当简单:
1 2 3 4 5 |
var firstTwoLetters = function(words){ return _.map(words,function(word){ return _.first(word,2); }); }; |
看!看JavaScript巫术。我正在使用这些高级的函数式应用函数,像_.map 和 _.first。你还有什么要说的,利兰(译注:作者Leland)?
尽管underscore 和 像_.map这样的函数是非常有价值的函数式范式,但是像这个例子中所采用的组织代码的方法看起来…冗长而且对于我来说太难于理解。我们真的需要这样做吗?
如果开始思考的时候多一点“函数式”的思维,可能我们能够把上面的例子改成这样:
1 2 |
// ...一点魔法 var firstTwoLetters = map(first(2)); |
仔细想想,在1行代码中包含了和上面5行代码同样的信息。words 和word 仅仅是参数/占位符。这个方法的核心是用一种更明显的方式组合map函数,first函数,和常量2。
诸位可能会在这个例子中寻找,什么会是其中的“一点魔法”。最终,把像上面提到的“一点魔法”放到任何一个例子中…某种小伎俩,不是吗?好吧,我会在接下来的文章中阐释“一点魔法”,所以呢,如果你有点好奇,请继续关注!
这个系列的博客文章目的是帮助人们了解如何在编写JavaScript程序中借鉴那些函数式编程语言的美好之处。
在下一篇文章中,我会讨论JavaScript语言中那些函数式的元素和非函数式的元素。有了这些知识,我们会慢慢的拼凑出在JavaScript中一些函数式编程的基础构件。
更多内容预告:
- 第一部分:引言
- 第二部分:如何打造“函数式”编程语言
- 第三部分:.apply()、.call()以及arguments对象
- 第四部分:函数柯里化
- 第五部分:参数可变函数(敬请期待)
- 第六部分:一个真实的例子——2048 Game & Solver(敬请期待)
- 第七部分:惰性序列 / 集合(敬请期待)
- 第八部分:参数顺序为何重要(敬请期待)
- 第九部分:Functors 和 Monads(敬请期待)