用递归的方式处理数组 && 把递归方法方法定义到数组的原型上 (这是一次脑洞大开的神奇尝试)
在 javascript 里,如果我们想用一个函数处理数组 (Array) 中的每个元素,那我们有很多种选择,最简单的当然就是用自带的 forEach 函数(低版本也可以使用 lodash 中的 forEach 函数):
const arr = [0,1,2,3,4,5,6,7,8,9];
arr.forEach(item=>{ console.log(item) });//依次输出
除了这种遍历,数组还有一种很常用的操作,就是拿来递归,js中的数组自带了 pop 和 push 方法,其实也可以当作一个链表来用,配合递归自然也是相当好用:
const arr = [0,1,2,3,4,5,6,7,8,9];
const func = (arr)=>{
item = arr.pop();
console.log(item);
if (arr.length==0) return;
return func(arr);
}
func(arr)
这样也能实现和之前 forEach 类似的效果~
既然效果差不多,那我们为啥要搞出这么麻烦的东西??
嘛……有些场景下遍历操作也不是那么好用的啦……比如我以前博文中写到的那个爬虫
"use strict"
const request = require('request')
const fs = require('fs')
const arr = [
'http://path.to/img1.jpg',
'http://path.to/img2.jpg',
'http://path.to/img3.jpg',
...
'http://path.to/img498.jpg',
'http://path.to/img499.jpg',
'http://path.to/img500.jpg'
]
arr.forEach(src=> {
//下载图片
const ws = fs.createWriteStream('./download/'+src.split('/').pop());
ws.on('close', ()=>{
console.log('下载完成')
})
request(src).pipe(ws);
})
因为 request 是一个异步操作,所以它并不会阻塞 forEach ,也就是说上面这个 demo 一旦运行起来,就会创建500个并发的网络请求和文件写入……
这就不太好玩了,一般来说并发请求可以提高网络利用效率,但效率再怎么提高,带宽也是有限的,并发过多就会导致单个请求变慢,请求过慢就可能会被服务端干掉,被服务端干掉的话我们就拿不到想要的图片了
所以我们期望的效果是依次执行下载操作,下载完一个再去下载另一个,这时候就比较适合用递归了~
"use strict"
const request = require('request')
const fs = require('fs')
const arr = [
'http://path.to/img1.jpg',
'http://path.to/img2.jpg',
'http://path.to/img3.jpg',
...
'http://path.to/img498.jpg',
'http://path.to/img499.jpg',
'http://path.to/img500.jpg'
]
const download = (arr)=>{
src = arr.pop();
//下载图片
const ws = fs.createWriteStream('./download/'+src.split('/').pop());
ws.on('close', ()=>{
console.log('下载完成')
if (arr.length>0)
return download(arr);
})
request(src).pipe(ws);
}
download (arr);
这样我们就可以依次下载图片啦~
可是既然是经常会用的东西……有没有更方便的用法啊,就像forEach那样的……?
那把递归这个操作抽象出来,直接定义到数组的原型 (prototype) 上吧
Array.prototype.recursion = function (func) {
const re = function (arr) {
if (!arr.length) return;
const item = arr.pop();
return func(item, function () {
return re(arr);
});
}
re(this);
}
于是乎这样随便写了一下,虽然很简陋,但好歹是可以用的, 使用方式如下:
"use strict"
const request = require('request')
const fs = require('fs')
const arr = [
'http://path.to/img1.jpg',
'http://path.to/img2.jpg',
'http://path.to/img3.jpg',
...
'http://path.to/img498.jpg',
'http://path.to/img499.jpg',
'http://path.to/img500.jpg'
]
arr.recursion((src, next)=> {
//下载图片
const ws = fs.createWriteStream('./download/'+src.split('/').pop());
ws.on('close', ()=>{
console.log('下载完成');
//当前异步操作完成后,调用next来进行下一次操作
next()
})
request(src).pipe(ws);
})
其实我也不知道这样做是否合适,链表加递归这种做法毕竟还是更适合函数式风格,而操作原型这种做法更多的则是面向对象风格,函数式编程比较强调无副作用,而显然……我现在这种做法是有副作用的,递归过程中不断pop(),递归完成后,arr 就变成一个空数组了。
其实这也还只是一个半成品,我们可能还希望在递归完成的时候,再继续执行一些操作,比如说把下载下来的图片打个压缩包?或者发一条消息告诉我文件都下载完成了之类的。
不管怎么说,这也是一个思路,如果发现这个思路中有其他严重的问题,或者有更好的建议,也欢迎指教~
用递归的方式处理数组 && 把递归方法方法定义到数组的原型上 (这是一次脑洞大开的神奇尝试)的更多相关文章
- 大数据学习day13------第三阶段----scala01-----函数式编程。scala以及IDEA的安装,变量的定义,条件表达式,for循环(守卫模式,推导式,可变参数以及三种遍历方式),方法定义,数组以及集合(可变和非可变),数组中常用的方法
具体见第三阶段scala-day01中的文档(scala编程基础---基础语法) 1. 函数式编程(https://www.cnblogs.com/wchukai/p/5651185.html): ...
- php中对象转数组有哪些方法(总结测试)
php中对象转数组有哪些方法(总结测试) 一.总结 一句话总结:json_decode(json_encode($array),true)和array强制转换(或带递归) 1.array方式强制转换对 ...
- 【前端基础系列】slice方法将类数组转换数组实现原理
问题描述 在日常编码中会遇到将类数组对象转换为数组的问题,其中常用到的一种方式使用Array.prototype.slice()方法. 类数组对象 所谓的类数组对象,JavaScript对它们定义为: ...
- java基础:方法的定义和调用详细介绍,方法同时获取数组最大值和最小值,比较两个数组,数组交换最大最小值,附练习案列
1. 方法概述 1.1 方法的概念 方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 注意: 方法必须先创建才可以使用,该过程成为方法定义 方法创建后并不是直接可 ...
- javascript中数组的concat()方法 - 数组连接
<html> <head> <title>数组的concat()方法</title> <script> /* 数组的concat()方法: ...
- php中获得数组长度的方法
php中获得数组长度的方法 count统计数组里元素的个数: strlen是统计数组中元素的长度: 你如果想统计数组中所有元素的长度,那就用循环统计吧tqeb 代码: $a = array( ...
- 【前端_js】javascript中数组的map()方法
数组的map()方法用于遍历数组,每遍历一个元素就调用回调方法一次,并将回调函数的返回结果作为新数组的元素,被遍历的数组不会被改变. 语法:let newAarray = arr.map(functi ...
- php用压栈的方式,循环遍历无限级别的数组(非递归方法)
php用压栈的方式,循环遍历无限级别的数组(非递归方法) 好久不写非递归遍历无限级分类...瞎猫碰到死老鼠,发刚才写的1段代码,压栈的方式遍历php无限分类的数组... php压栈的方式遍历无限级别数 ...
- js数组去重 数组拼接 替换数组中的指定值 递归数组 判断数组中是否存在指定值 数组求和 根据条件判数组值
这是学习过程中记录的一些关于数组操作的常用属性或方法,记录一下方便以后使用. // 数组去重 var arr1 = [1,1,2,3,4,5,6,3,2,4,5,'a','b','c','a',6,7 ...
随机推荐
- POJ1556(割点)
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8114 Accepted: 3716 Description C ...
- HDU3410(单调队列)
Passing the Message Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- Java各种工具下载
http://yunpan.cn/cyUzqFTu8pEER 提取码 355c myeclipse2013 http://yunpan.cn/cyUzPi7nC8Z9S 提取码 fc4b my ...
- 深圳尚学堂:JavaScript的常见面试题
经常说编程是一门技术专业,在找工作时面试官肯定不止看你的面试能力,还要看你的专业知识掌握,他可能会让你做一个小的编程测试,或者说考察你的语法知识掌握,今天,总结了一些关于在JavaScript中常常会 ...
- [html5] 学习笔记-响应式布局
1.响应式布局介绍 响应式布局是2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端——而不是每一个终端做一个特定的版本.这个概念是为了兼容移动互联网浏览而诞生的,其目的是为用户提供 ...
- Codeforces 708A Letters Cyclic Shift
A. Letters Cyclic Shift time limit per test:1 second memory limit per test:256 megabytes input:stand ...
- vs基础:无法断点调试dll项目 无法命中
调试vs时,经常会出现,你设置了dll项目的一些断点,可f5之后,这些断点无效.时代定制的程序组的童鞋告诉你解决方法:在解决方案上右键“属性”,点击左侧树“配置属性”-->“配置”,右侧项目列表 ...
- Python学习--20 Web开发
HTTP格式 HTTP协议是基于TCP和IP协议的.HTTP协议是一种文本协议. 每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的. HTTP ...
- 用js实现文字提示层 ---总结
文字提示层在项目中应该是比较常见的,我工作中项目中就用到了,原理是一样,只不过形式不一样,今天通过看视频学习,学会了,总结下: 首先,页面效果如下: 需求: 当鼠标移入到红色字体是,提示框会显示在下 ...
- NHibernate的常见问题及解决方案
问题1 : 异常:in expected: <end-of-text> (possibly an invalid or unmapped class name was used in th ...