IT科技类资讯

反思JavaScript:论for循环的死亡

时间:2010-12-5 17:23:32  作者:人工智能   来源:人工智能  查看:  评论:0
内容摘要:我们一直在使用JavaScript的for循环。但现在,在最新的函数式编程技巧的支持下,过时的它应该退休了。幸运的是,你不必是一个函数式编程大师,也可以做出这个改变。更幸运的是,这就是你在眼前项目中可

我们一直在使用JavaScript的反思for循环。但现在,循环在最新的反思函数式编程技巧的支持下,过时的循环它应该退休了。幸运的反思是,你不必是循环一个函数式编程大师,也可以做出这个改变。反思更幸运的循环是,这就是反思你在眼前项目中可以立马做的事情!

我们一直在使用JavaScript的循环for循环。但现在,反思在最新的循环函数式编程技巧的支持下,过时的反思它应该退休了。

幸运的循环是,你不必是反思一个函数式编程大师,也可以做出这个改变。网站模板更幸运的是,这就是你在眼前项目中可以立马做的事情!

那到底JavaScript的for循环有什么问题?

for循环设计本身鼓励改变状态以及产生副作用,这两者都是导致错误和不可预知代码的隐患。

我们都知道全局状态是糟糕的,应该避免。可是,局部状态和全局状态一样糟糕,只是因为局部状态处于一个较小的尺度中,没有引起注意。因此,我们从来没有真正解决问题,而是尽量把问题最小化。

对于可变的状态,在一些未知的时间点,变量会因为某些未知的原因而改变。这时,源码库你要花上数小时进行调试,寻找这个值改变的原因。光为这,我都不知道自己掉了多少把头发了。

下面,我想简单谈谈副作用。这个词听起来就烦人,副作用……妈蛋!难道你会希望自己的程序有什么副作用?当然不!

但什么是副作用?

当一个函数修改了其作用域以外的某些东西时,它就被视为有副作用。可以是改变一个变量的值、读取键盘输入、调用某个API、写入磁盘数据、打印日志,等等。

副作用很强大,但同时也被承担着重大的责任。

副作用应该尽可能被消除,或者封装在内部,或可控。有副作用的函数难以测试,也难以推断,所以要尽你所能甩掉它。亿华云幸好这里可以不用担心副作用。

好了,闲话少说,上代码。我们看一下这段或许你已经看过上千次典型的for循环:

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里的声明抽象为一个函数:

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)   } } 

通常,抽出if语句是个不错的做法。过滤的着眼点从“小于7个月”转变为“是一只小猫”非常非常重要。现在,当你再看这段代码,意图就变得清晰了。为什么要取得小于7个月的猫?一点都不明确。我们的意图是找到小猫,所以让代码表示出来!

另一个好处是iskitten现在可复用了,而且我们都明白:

让代码可复用应该始终是我们的目标之一。

下一个改变就是提取出从对象猫到猫名字的转换(或者映射)。这个变化对以后更有意义,现在只要相信我就好了:

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]))   } } 

我本打算先介绍一下filter和map的,但转念一想,还是直接展示引入它们之后的代码多好理解,更能让你体会到代码可读性的巨大变化:

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

还要注意,我们已经消除了 kittens.push(...)。不再有可变的状态,也不再有var!

使用const的代码有如魔鬼般性感(超过了var和let)。

这里说明下,我们自始至终都可以使用const,因为const并不会使对象本身不可变(这个咱们下次再说)。别急,这里只是在讲一个范例,所以先放我一马!

重构的最后一步就是把过滤和映射方法也提取到一个函数里(为了复用嘛,你懂的):

整合一起就是这样:

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) 

你会如何进一步分解这些函数?仔细想想“小于”或者name属性、map或filter,说不定能有额外的收获。你还可以研究下函数的复合,收益更大。

原    文:Rethinking JavaScript: Death of the For Loop

译    文:众成翻译

作    者:camiler
copyright © 2025 powered by 益强资讯全景  滇ICP备2023006006号-31sitemap