资讯专栏INFORMATION COLUMN

JavaScript For 循环的函数式改造

icattlecoder / 1920人阅读

摘要:循环的函数式改造翻译自。循环的设计思想深受可变状态与副作用的影响,不过函数式编程中认为可变状态与副作用是导致潜在错误与不可预测性的罪魁祸首,是应该尽力避免的模式。

JavaScript For 循环的函数式改造翻译自Rethinking JavaScript: Death of the For Loop。前两天笔者整理了一篇JavaScript 函数式编程导论,笔者个人不是很喜欢彻底的函数式编程化,在复杂逻辑处理与性能上可能都存在部分问题。不过借鉴函数式编程的思想去改造部分代码片以提高其可读性与可测试性还是蛮有好处的,此篇文章以 For-Loop 入手,笔者觉得讲得蛮好的。

For 循环的设计思想深受可变状态与副作用的影响,不过函数式编程中认为可变状态与副作用是导致潜在错误与不可预测性的罪魁祸首,是应该尽力避免的模式。众所周知,使用全局状态会污染局部代码,而同样的局部状态同样会导致与全局状态一样的问题,只不过因为局部状态的影响被限制在较小的影响范围内,因此不像全局状态那样的突兀。允许可变的状态也就意味着变量可能因为未知的原因被改变,开发者可能要花费数小时的时间去定位到底是哪一段代码修改了这个变量值。在过去的开发岁月里,我就是因为这样变秃了,却似乎没有变强。
另一方面,任何修改除了作用域内变量值的函数都被称为有副作用的函数。典型的譬如修改全局变量、读入键盘输入、调用远程 API 、写入磁盘等等。副作用的功效强大,我们应该尽可能地将其封装与控制在一定范围内。大道理就回顾到这里,下面我们直接看下代码:

const cats = [
  { name: "Mojo",    months: 84 },
  { name: "Mao-Mao", months: 34 },
  { name: "Waffles", months: 4 },
  { name: "Pickles", months: 6 }
]
var kittens = []
//典型的 for 循环用法
for (var i = 0; i < cats.length; i++) {
  if (cats[i].months < 7) {
    kittens.push(cats[i].name)
  }
}
console.log(kittens)

我们改造的第一步是将if语句中的逻辑判断提取出来,老实说提取之后笔者觉得正好符合Clean JavaScript:写出整洁的JavaScript代码里面提及的让变量名而不是注释表述其含义的效果:

const isKitten = cat => cat.months < 7
var kittens = []
for (var i = 0; i < cats.length; i++) {
  if (isKitten(cats[i])) {
    kittens.push(cats[i].name)
  }
}

这种方式一方面增加了代码的可用性,另一方面也保证了我们测试条件的可测试性,特别是当我们的逻辑判断很复杂的时候。下面我们是将属性提取也抽象出来:

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
var kittens = []
for (var i = 0; i < cats.length; i++) {
  if (isKitten(cats[i])) {
    kittens.push(getName(cats[i]))
  }
}

下面我们可以用函数式中的过滤与转换函数来描述这个过程:

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
const kittens =
  cats.filter(isKitten)
      .map(getName)

到这里我们摒弃了push函数,即移除了可变状态的介入。最后的重构即是将我们的过滤与转换过程再进行一层封装,使其成为可复用的过程:

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
const getKittenNames = cats =>
  cats.filter(isKitten)
      .map(getName)
const cats = [
  { name: "Mojo",    months: 84 },
  { name: "Mao-Mao", months: 34 },
  { name: "Waffles", months: 4 },
  { name: "Pickles", months: 6 }
]
const kittens = getKittenNames(cats)
console.log(kittens)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81217.html

相关文章

  • EventEmitter:从命令 JavaScript class 到声明函数华丽转身

    摘要:典型和改造挑战了解事件发布订阅系统实现思想,我们来看一段简单且典型的基础实现上面代码,实现了一个类我们维护一个类型的,对不同事件的所有回调函数进行维护。方法对指定事件进行回调函数存储方法对指定的触发事件,逐个执行其回调函数。 showImg(https://segmentfault.com/img/remote/1460000014287200); 新书终于截稿,今天稍有空闲,为大家奉...

    hsluoyz 评论0 收藏0
  • EventEmitter:从命令 JavaScript class 到声明函数华丽转身

    摘要:典型和改造挑战了解事件发布订阅系统实现思想,我们来看一段简单且典型的基础实现上面代码,实现了一个类我们维护一个类型的,对不同事件的所有回调函数进行维护。方法对指定事件进行回调函数存储方法对指定的触发事件,逐个执行其回调函数。 showImg(https://segmentfault.com/img/remote/1460000014287200); 新书终于截稿,今天稍有空闲,为大家奉...

    dadong 评论0 收藏0
  • JavaScript函数编程二(翻译)

    摘要:原文链接原文作者函数式编程这篇文章是介绍函数式编程的四篇文章中的第二篇。这些部分被使用的越来越频繁,人们把他们放到一个函数式编程的库里面,有一些流行的库包括未亡待续阅读下一节原文地址欢迎关注 showImg(https://segmentfault.com/img/bVtSez); tips 原文链接: http://jrsinclair.com/articles/2016/gentl...

    smartlion 评论0 收藏0
  • JavaScript 函数编程技巧 - 柯里化

    摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。在一些函数式编程语言中,会定义一个特殊的占位变量。个人理解不知道对不对延迟执行柯里化的另一个应用场景是延迟执行。不断的柯里化,累积传入的参数,最后执行。作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 这里可以对照另外一篇介绍 JS 反柯里化 的文章一起看~ 1. 简介 柯里化(Currying)...

    edgardeng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<