百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

[Effective JavaScript 笔记]第50条:迭代方法优于循环

myzbx 2025-07-03 18:16 33 浏览

"懒"程序员才是好程序员。复制和粘贴样板代码,一但代码有错误,或代码功能修改,那么程序在修改的时候,程序员需要找到所有相同功能的代码一处处进行修改。这会使人重复发明轮子,而且在别人看代码的时候无法在更高层次都看待问题的解决方案。太容易陷入细节。

for循环

js中的for循环在进行一些细微变化时,可以引入不同的行为。编程的时候对于边界条件的判断往往会导致一些简单的错误。下面的一些for循环的细微变化导致边界条件的变化。

for(var i=0;i<=n;i++){...}
//包括最后的迭代
for(var i=1;i< n;i++){...}
//忽略第一次迭代
for(var i=n;i>=0;i--){...}
//包括第一次迭代
for(var i=n-1;i > 0;i++){...}
//忽略最后的迭代

在这里都是对终止条件的一个设置。这里可以有很多的方式,可以使终止条件发生错误。js的闭包是一种为这些模式建立迭代抽象方便的、富有表现力的手法,可以避免重复代码。

ES5中数组方法

其中ES5中提供的数组方法就包含很多。比如

Array.prototype.forEach

比如下面这段对数组的循环。

for(var i=0,n=players.length;i< n;i++){
    players[i].score++;
}

使用数组的迭代方法,可以改写为

players.forEach(function(p){
    p.score++;
});

上面的代码把循环的方式进行抽象,把要执行的具体代码通过函数传递闭包,完成对数组元素的操作及访问。这里消除了终止条件和任何数组索引。

Array.prototype.map

完成对数组的每个元素进行一些操作后建立一个新的数组。

使用循环
var trimmed=;
for(var i=0,n=input.length;i< n;i++){
    trimmed.push(input[i].trim);
}

使用forEach
var trimmed=;
input.forEach(function(s){
    trimmed.push(s.trim);
});

使用map
var trimmed=input.map(function(s){
    return s.trim;
});

Array.prototype.filter

计算一个数组建立一个新数组,该数组只包含有数组的一些元素filter方法需要一个谓词函数,如果元素应该存在于新数组中则返回真值,如果元素应该被剔除则返回假值。例如,可以从价格表中提取出一个特定价格区间的列表。

listings.filter(function(listing){
    return listing.price>=min&&listing.price<=max;
});

以上的forEach,map,filter三个方法都是ES5中,数组的默认方法。下面实现一个自己的迭代抽象。例:提取出满足谓词函数的数组的前几个元素,直到不满足的元素终止,不管后面是否有元素满足条件。

function takeWhile(a,pred){
   var res=;
   for(var i=0,n=a.length;i < n;i++){
      if(!pred(a[i],i)){
 break;
      }
      res[i]=a[i];
   }  
   return res;
}

var prefix=takeWhile([1,2,3,4,26,18,9],function(n){
    return n<10;
});
prefix;//[1, 2, 3, 4]

上面pred函数有两个参数,而下面的回调我们只传入了一个参数。对第二个参数没有进行处理,这里是无所谓的。

猴子补丁

把takeWhile函数添加到Array.prototype中使其成为一个方法。

Array.prototype.takeWhile=function(pred){
    var res=;
    for(var i=0,n=this.length;i < n;i++){
      if(!pred(this[i],i)){
 break;
      }
      res[i]=this[i];
    }  
    return res;
};
var prefix=[1,2,3,4,26,18,9].takeWhile(function(n){
    return n<10;
});
prefix;//[1, 2, 3, 4]

循环控制流操作

只有一点循环优于迭代,循环可以控制流操作,如break和continue。例如,使用forEach方法来实现takeWhile函数

function takeWhile(a,pred){
    var res=;
    a.forEach(function(x,i){
        if(!pred(x)){
 //?
        }
        res[i]=x;
    });
    return res;
}

上面的代码怎么终止该循环的当次执行。

内部异常

function takeWhile(a,pred){
    var res=;
    var earlyExit={};
    try{
        a.forEach(function(x,i){
 if(!pred(x)){
 throw earlyExit;
 }
 res[i]=x;
        });
    }catch(e){
        if(e!==earlyExit){
 throw e;
        }
    }
    return res;
}

这样的处理方法,把原本简单的处理变得更加复杂了,不可取。

some,every

有没更简单的方法呢。下面看一下数组提供的用于提前终止循环的方法。some和every。

some方法返回一个布尔值表示其回调对数组的任何一个元素是否返回一个真值。

本人理解:

所有元素,对于传入的函数的判断,有一真则为真。全为假才为假。

相当于所有元素执行函数后取或。

[1,10,100].some(function(x){return x>5;});//true
[1,10,100].some(function(x){return x<0;});//false

every方法返回一个布尔值表示其回调函数是否对所有元素返回一个真值。

本人理解:

所有元素,对于传入的函数的判断,有一假则为假。全为真才为真。

相当于所有元素执行函数后取且。

[1,10,100].every(function(x){return x>5;});//false
[1,10,100].every(function(x){return x>0;});//true

这两个方法都是短路循环。只要产生的结果可以决定最后结果后,就不再执行后面的循环。即some一旦产生一个真值,则立即返回。every一旦产生一个假值,也立即返回。利用它们的特点,改写takeWhile函数。

function takeWhile(a,pred){
    var res=;
    a.every(function(x,i){
        if(!pred(x)){
 return false;//break
        }
        res[i]=x;
        return true;
    });
    return res;
}

提示

  • 使用迭代方法替换for循环使得代码可读,并且避免了重复循环控制逻辑

  • 使用自定义的迭代函数来抽象未被标准库支持的常见循环模式

  • 在需要提前终止循环的情况下,仍然推荐使用传统的循环。另外,some和every方法也可用于提前退出

相关推荐

如何设计一个优秀的电子商务产品详情页

加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品电子商务网站的产品详情页面无疑是设计师和开发人员关注的最重要的网页之一。产品详情页面是客户作出“加入购物车”决定的页面...

怎么在JS中使用Ajax进行异步请求?

大家好,今天我来分享一项JavaScript的实战技巧,即如何在JS中使用Ajax进行异步请求,让你的网页速度瞬间提升。Ajax是一种在不刷新整个网页的情况下与服务器进行数据交互的技术,可以实现异步加...

中小企业如何组建,管理团队_中小企业应当如何开展组织结构设计变革

前言写了太多关于产品的东西觉得应该换换口味.从码农到架构师,从前端到平面再到UI、UE,最后走向了产品这条不归路,其实以前一直再给你们讲.产品经理跟项目经理区别没有特别大,两个岗位之间有很...

前端监控 SDK 开发分享_前端监控系统 开源

一、前言随着前端的发展和被重视,慢慢的行业内对于前端监控系统的重视程度也在增加。这里不对为什么需要监控再做解释。那我们先直接说说需求。对于中小型公司来说,可以直接使用三方的监控,比如自己搭建一套免费的...

Ajax 会被 fetch 取代吗?Axios 怎么办?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!今天给大家带来的主题是ajax、fetch...

前端面试题《AJAX》_前端面试ajax考点汇总

1.什么是ajax?ajax作用是什么?AJAX=异步JavaScript和XML。AJAX是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实...

Ajax 详细介绍_ajax

1、ajax是什么?asynchronousjavascriptandxml:异步的javascript和xml。ajax是用来改善用户体验的一种技术,其本质是利用浏览器内置的一个特殊的...

6款可替代dreamweaver的工具_替代powerdesigner的工具

dreamweaver对一个web前端工作者来说,再熟悉不过了,像我07年接触web前端开发就是用的dreamweaver,一直用到现在,身边的朋友有跟我推荐过各种更好用的可替代dreamweaver...

我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊

接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...

福斯《死侍》发布新剧照 &quot;小贱贱&quot;韦德被改造前造型曝光

时光网讯福斯出品的科幻片《死侍》今天发布新剧照,其中一张是较为罕见的死侍在被改造之前的剧照,其余两张剧照都是死侍在执行任务中的状态。据外媒推测,片方此时发布剧照,预计是为了给不久之后影片发布首款正式预...

2021年超详细的java学习路线总结—纯干货分享

本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础重点知识点:数据类型、核心语法、面向对象...

不用海淘,真黑五来到你身边:亚马逊15件热卖爆款推荐!

Fujifilm富士instaxMini8小黄人拍立得相机(黄色/蓝色)扫二维码进入购物页面黑五是入手一个轻巧可爱的拍立得相机的好时机,此款是mini8的小黄人特别版,除了颜色涂装成小黄人...

2025 年 Python 爬虫四大前沿技术:从异步到 AI

作为互联网大厂的后端Python爬虫开发,你是否也曾遇到过这些痛点:面对海量目标URL,单线程爬虫爬取一周还没完成任务;动态渲染的SPA页面,requests库返回的全是空白代码;好不容易...

最贱超级英雄《死侍》来了!_死侍超燃

死侍Deadpool(2016)导演:蒂姆·米勒编剧:略特·里斯/保罗·沃尼克主演:瑞恩·雷诺兹/莫蕾娜·巴卡林/吉娜·卡拉诺/艾德·斯克林/T·J·米勒类型:动作/...

停止javascript的ajax请求,取消axios请求,取消reactfetch请求

一、Ajax原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。停止javascript的ajax请求...