Searching...
简体中文
English
Español
简体中文
Français
Deutsch
日本語
Português
Italiano
한국어
Русский
Nederlands
العربية
Polski
हिन्दी
Tiếng Việt
Svenska
Ελληνικά
Türkçe
ไทย
Čeština
Română
Magyar
Українська
Bahasa Indonesia
Dansk
Suomi
Български
עברית
Norsk
Hrvatski
Català
Slovenčina
Lietuvių
Slovenščina
Српски
Eesti
Latviešu
فارسی
മലയാളം
தமிழ்
اردو
Functional JavaScript

Functional JavaScript

Introducing Functional Programming with Underscore.js
by Michael Fogus 2013 258 pages
Programming
Technology
Computer Science
8 minutes

重点摘要

1. JavaScript通过一等函数支持函数式编程

一等函数是指可以像其他值一样随处使用的函数——几乎没有限制。

函数作为值。 在JavaScript中,函数可以赋值给变量,作为参数传递给其他函数,从函数中返回,并存储在数据结构中。这种灵活性使得函数式编程技术成为可能。例如:

  • 将函数赋值给变量:var square = function(x) { return x * x; }
  • 将函数作为参数传递:[1, 2, 3].map(function(x) { return x * 2; })
  • 返回一个函数:function makeAdder(x) { return function(y) { return x + y; }; }

函数的一等性质是JavaScript中许多函数式编程模式的基础。

2. 高阶函数是函数式JavaScript的关键

捕获其他函数的高阶函数是构建抽象的非常强大的技术。

强大的抽象。 高阶函数要么将函数作为参数,要么返回函数作为结果。它们使得强大的抽象和代码重用成为可能。常见的例子包括:

  • map:转换集合中的每个元素
  • reduce:将集合的元素组合成一个值
  • filter:根据谓词选择集合中的元素

这些函数允许你简洁地表达复杂的操作并组合行为。例如:

const numbers = [1, 2, 3, 4, 5];
const evenSquares = numbers
  .filter(x => x % 2 === 0)
  .map(x => x * x);

这段代码清晰地表达了选择偶数并将其平方的意图,而无需显式管理循环或中间数组。

3. 闭包在JavaScript中实现强大的函数式技术

闭包是一个捕获其定义范围内的外部绑定(即,不是其自身参数)的函数,以便在以后使用(即使在该范围完成之后)。

封装和状态。 闭包允许函数“记住”并访问其外部范围的变量,即使在该范围执行完毕之后。这使得:

  • 私有状态:创建仅通过特定函数访问的变量
  • 函数工厂:根据参数生成专门的函数
  • 部分应用:通过固定现有函数的一些参数创建新函数

维护私有状态的闭包示例:

function counter() {
  let count = 0;
  return function() {
    return ++count;
  };
}

const increment = counter();
increment(); // 1
increment(); // 2

count变量不能直接访问,但返回的函数可以访问和修改它。

4. 函数组合允许从简单部分构建复杂行为

函数式编程是关于将程序拆开并从相同的部分重新组装起来,抽象在函数边界后面。

构建复杂性。 函数组合是将两个或多个函数组合成一个新函数的过程。这允许你:

  • 从简单、可重用的部分创建复杂行为
  • 通过分解复杂操作提高代码可读性
  • 通过隔离和测试较小的功能单元提高可维护性

组合可以通过各种方式实现:

  • 手动组合:const f = x => h(g(x))
  • 工具函数:const compose = (f, g) => x => f(g(x))
  • 像Ramda或Lodash/FP这样的库

通过组合构建数据处理管道的示例:

const processData = compose(
  summarize,
  filterOutliers,
  normalize,
  parseInput
);

这清晰地表达了数据处理的步骤,而不会使代码充满实现细节。

5. 纯函数和不可变性导致更可预测的代码

使用纯函数编程可能看起来非常有限。[...] 然而,当你对状态变异采取自由主义观点时,你实际上是在限制组合的可能性,复杂化你推理任何给定语句效果的能力,并使测试代码变得更加困难。

可预测性和可测试性。 纯函数对于给定的输入总是产生相同的输出,并且没有副作用。这与不可变数据结合:

  • 简化了对代码行为的推理
  • 促进了更容易的测试和调试
  • 使并行化和记忆化变得安全

保持纯度和不可变性的策略:

  • 对不应改变的变量使用const
  • 创建新对象/数组而不是修改现有的
  • 使用像Immutable.js这样的库来实现高效的不可变数据结构

纯函数的示例:

function addToCart(cart, item) {
  return [...cart, item];
}

这个函数不会修改原始购物车,使得跟踪变化和预测行为变得更容易。

6. 递归在函数式编程中提供了循环的替代方案

使用递归,状态通过函数参数管理,变化通过从一个递归调用到下一个递归调用的参数建模。

优雅的解决方案。 递归通常为涉及层次结构或重复结构的问题提供更优雅和简洁的解决方案。好处包括:

  • 一些算法的自然表达(例如,树遍历)
  • 避免与循环相关的可变状态
  • 编译器优化的潜力(尾调用优化)

然而,要注意JavaScript中的堆栈溢出风险,大多数环境中缺乏尾调用优化。缓解此问题的技术包括:

  • 跳板:将递归调用包装在thunks中
  • 续延传递风格:显式管理调用栈

将嵌套数组展平的递归函数示例:

function flatten(arr) {
  return arr.reduce((flat, next) => 
    flat.concat(Array.isArray(next) ? flatten(next) : next), 
  []);
}

7. 函数式编程促进数据流和转换管道

管道应该是纯粹的——没有数据因通过管道而受到损害。

清晰的数据转换。 函数式编程鼓励以数据通过一系列转换的方式思考。这种方法:

  • 通过清晰展示数据处理的步骤提高代码可读性
  • 通过分离关注点提高可维护性
  • 促进并行化和优化

构建管道的技术:

  • 方法链(例如,使用lodash)
  • 纯函数的组合
  • 专门的库,如RxJS用于异步数据流

数据处理管道的示例:

const processOrders = pipe(
  fetchOrders,
  filterValidOrders,
  calculateTotals,
  generateReport
);

这清晰地展示了处理订单的步骤,而不会陷入实现细节。

8. 基于Mixin的设计提供了对象组合的函数式方法

简单的数据是最好的。专门的数据类型应该是特殊的。

灵活的组合。 Mixin提供了一种在不依赖于经典继承的情况下组合对象行为的方法。这种方法:

  • 允许更灵活和模块化的代码设计
  • 避免了与深层继承层次结构相关的问题
  • 促进了面向对象编程的函数式风格

在JavaScript中实现Mixin:

  • 使用Object.assign()将方法复制到对象原型上
  • 使用高阶函数创建应用Mixin的工厂函数

创建具有Mixin的对象的示例:

const withLogging = (obj) => ({
  ...obj,
  log: (msg) => console.log(`[${obj.name}]: ${msg}`)
});

const withValidator = (obj) => ({
  ...obj,
  validate: () => { /* validation logic */ }
});

const createUser = (name) => 
  withValidator(withLogging({ name, data: {} }));

这种方法允许灵活地组合对象行为,而无需僵化的类层次结构。

Last updated:

评论

4.07 out of 5
Average of 100+ ratings from Goodreads and Amazon.

《Functional JavaScript》获得了大多数正面评价,平均评分为4.07分(满分5分)。读者们赞赏书中对JavaScript中函数式编程概念的清晰解释,称赞其直截了当的方式和实用的例子。许多人认为这本书让他们大开眼界,对提升编程技能非常有价值。一些评论者指出书中的内容较为密集,建议中级到高级程序员阅读。尽管有少数人批评其对Underscore.js的依赖,并质疑其在实际应用中的适用性,但大多数人认为这是一本关于JavaScript中函数式编程技术的扎实入门书籍。

关于作者

Michael Fogus 是一位经验丰富的软件开发人员和作家,以其在函数式编程方面的专业知识而闻名。他撰写了多本关于编程的书籍,包括《The Joy of Clojure》和《Functional JavaScript》。Fogus 因其能够清晰简洁地解释复杂概念而受到尊敬。他的工作经常集中在将函数式编程原则应用于各种语言,特别是 JavaScript。Fogus 还因其对 Clojure 社区的贡献以及参与开发编程语言而闻名。他的写作风格因其直截了当和启发性而受到赞誉,使得具有不同经验水平的读者都能轻松理解复杂主题。

0:00
-0:00
1x
Create a free account to unlock:
Bookmarks – save your favorite books
History – revisit books later
Ratings – rate books & see your ratings
Listening – audio summariesListen to the first takeaway of every book for free, upgrade to Pro for unlimited listening.
Unlock unlimited listening
Your first week's on us!
Today: Get Instant Access
Listen to full summaries of 73,530 books. That's 12,000+ hours of audio!
Day 5: Trial Reminder
We'll send you a notification that your trial is ending soon.
Day 7: Your subscription begins
You'll be charged on Sep 29,
cancel anytime before.
Compare Features Free Pro
Read full text summaries
Summaries are free to read for everyone
Listen to full summaries
Free users can listen to the first takeaway only
Unlimited Bookmarks
Free users are limited to 10
Unlimited History
Free users are limited to 10
What our users say
15,000+ readers
“...I can 10x the number of books I can read...”
“...exceptionally accurate, engaging, and beautifully presented...”
“...better than any amazon review when I'm making a book-buying decision...”
Save 62%
Yearly
$119.88 $44.99/yr
$3.75/mo
Monthly
$9.99/mo
Try Free & Unlock
7 days free, then $44.99/year. Cancel anytime.