JS Array数组几个循环实用方法总结
微信搜索【大奇测试开】,关注这个坚持分享测试开发干货的家伙。
背景
在平台前端开发过程中会有对接口数据的再处理,其中数组类型就是常见之一,实际场景中,比如表数据提取用于筛选或提取符合条件的自定义数据列表,还有更复杂如多个接口数据合并等,在自己JS编程有限能力下,往往用常规的 for
实现,但在复杂对象或多层循环处理中,可读性和逻辑性就显得差强人意。
const tb_data = [ {"title":"计划1","passed":10,"failed":0,"skipped":0}, {"title":"计划2","passed":5,"failed":3,"skipped":2}, {"title":"计划2","passed":15,"failed":2,"skipped":1} ]; const sum_result = {"passed":0, "failed":0, "skipped":0} // for循环需要临时变量,数组长度,并且通过下角标获取内层属性值,多层数据依此增加循环嵌套 for (let i=0; i<tb_data.length;i++) { sum_result.passed = sum_result.passed + tb_data[i].passed; sum_result.failed = sum_result.failed + tb_data[i].failed; sum_result.skipped = sum_result.skipped + tb_data[i].skipped; } console.log(sum_result) // 运行输出结果 // > Object { passed: 30, failed: 5, skipped: 3 }
经过资料查询学习和实际应用,这里总结一些实用的JS数组处理方法,学会这些往往能大大提升编程效率,这些方法分别是
forEach、
map、
filter, 不过在介绍语法和例子之前先给出两个的两个结论:
- 性能上:for循环 > forEach > map
- 可读性:forEach/map > for循环
这里不做扩展讨论和数据对比,因为在没有绝对数量级别的处理需求下无大感知差异,更多关注可读性和更易编程性。
forEach
方法对数组进行一次遍历,并将每个元素传递给回调函数,返回值为undefinded,不支持链式,一个简单循环打印的例子如下:
const datas = ['Da', 'Qi', 'DevTest']; datas.forEach((element, index) => console.log(index, element)); // > 0 "Da" // > 1 "Qi" // > 2 "DevTest"
语法和参数
基于ES6标准支持以下函数语法,官方地址[1]
// 箭头函数 forEach((element) => { /* ... / }) forEach((element, index) => { / ... / }) forEach((element, index, array) => { / ... */ })
// 回调函数 forEach(callbackFn) forEach(callbackFn, thisArg)
// 内联函数 forEach(function(element) { /* ... / }) forEach(function(element, index) { / ... / }) forEach(function(element, index, array){ / ... / }) forEach(function(element, index, array) { / ... */ }, thisArg)
callbackFn
为每个元素执行的函数,内部接受1到3个参数:
- element [必须] 数组循环处理中的当前元素
- index [可选] 数组处理元素的索引
- **array [可选] **方法正在操作的数组
**thisArg**[可选] 当作this值传给每个callback调用
关于这个 thisAry 网上的也找不到太多的场景应用的案例,从官方一个列子添加了两行打印试着理解一下,即内循环内 this代表了Counter(),并把当前逻辑处理后对象再传到下次回调。
function Counter() { this.sum = 0 this.count = 0 } Counter.prototype.add = function(array) { array.forEach(function countEntry(entry) { this.sum += entry; ++this.count console.log(entry) // 打印循环元素值 console.log(this) // 打印逻辑操作后对象 },this); }; const obj = new Counter(); obj.add([2, 5, 9]); // > 2 // > Object { sum: 2, count: 1, add: Object { } } // > 5 // > Object { sum: 7, count: 2, add: Object { } } // > 9 // > Object { sum: 16, count: 3, add: Object { } }
forEach() 本身是不支持的 continue 与 break 语句,虽然可以使用 return 实现效果但没必要,建议用更合适的方法如
.every()或
.some()。
实践例子
将开头的for方式使用forEach改写实现,循环处理从结构变得更简洁。
const tb_data = [ // 省略(参考文章for循环例子)... ]; const sum_result = {"passed":0, "failed":0, "skipped":0} tb_data.forEach((row) =>{ sum_result.passed = sum_result.passed + row.passed; sum_result.failed = sum_result.failed + row.failed sum_result.skipped = sum_result.skipped + row.skipped }); console.log(sum_result)
注意一点的是 forEach 循环中对其元素直接修改,对象类型的直接修改原对象数组,而单数字或者字符型数组无效,这时候只能通过创建的新的数组赋值,或通过原数组下角标的形式直接改。
map
顺序循环数组每一项,并返回一个本身后者逻辑操作后的 新数组 即回调函数的结果,支持链式,其中语法和参数使用同forEach,举个例子
const numbers = [1, 4, 9, 16]; const rt_array = numbers.map(x => x * 2); //const rt_array = numbers.map(x => {return x * 2}); // 完整写法 console.log(numbers); // 输出 Array [1, 4, 9, 16] console.log(rt_array); // 输出 Array [2, 8, 18, 32]
此方法可应用的场景但不限于数学计算、格式化或者提取对象等,这里不用开头for例子改写,用一个更能体现用处的另外一个例子。
const tables = [ {id:1, name:'提测平台', read: 100}, {id:2, name:'自动化报告平台', read: 200}, {id:3, name:'Mock平台', read: 150}, ]; var totalRead = 0 // 返回名字列所有值,并做个一个总数计算 const names = tables.map(row => { totalRead = totalRead + row.read return row.name }); console.log(totalRead) // 输出 450 console.log(names); // 输出 Array ["提测平台", "自动化报告平台", "Mock平台"]
filter
该 filter() 方法创建一个新数组,经filter函数回调条件值 ,若为真返回匹配的项,即常用的场景是对元素进行条件过滤。
语法和参数一样参考forEach,这回给个基本用法:
数组对象.filter(function(element, index, array){ /* 这里做些操作 */ })
然后再看个实际例子,先看下用for实现一个表格数据筛选,条件为通过率大于90%。
const tb_data = [ {"title":"计划1","passed":10,"failed":0,"skipped":0}, {"title":"计划2","passed":5,"failed":3,"skipped":2}, {"title":"计划2","passed":15,"failed":2,"skipped":1} ]; const filter_data = [] for (let i=0; i<tb_data.length;i++) { const sum = tb_data[i].passed + tb_data[i].failed + tb_data[i].skipped if (tb_data[i].passed / sum > 0.9) { filter_data.push(tb_data[i]) } } console.log(filter_data) // 输出 > Array [Object { title: "计划1", passed: 10, failed: 0, skipped: 0 }]
接着用
filter()改写下,看看如何让过滤处理更简单。
const tb_data = [ {"title":"计划1","passed":10,"failed":0,"skipped":0}, {"title":"计划2","passed":5,"failed":3,"skipped":2}, {"title":"计划2","passed":15,"failed":2,"skipped":1} ]; var rate_name = tb_data.filter(row => { return (row.passed / (row.passed + row.failed + row.skipped) > 0.9) }) console.log(rate_name) // 输出 > Array [Object { title: "计划1", passed: 10, failed: 0, skipped: 0 }]
总结和扩展
forEach、map、filter 均能在不同的逻辑场景下简化for代码对于数组处理的逻辑,并提高可读性,毕竟在前后端的代码接口中表格、列表类型的返回数据占了绝大多数。当然JS的Array还有更多的处理方式来使编程更加丝滑,按需可以参考 JavaScript-Array 这个教程。
另外由于笔者也没有系统学过JS,所以在这次整理有也了解的两个名词,简单理解下记录下。
箭头函数
Arrow Function(箭头函数)ES6标准新增了一种函数,即简化了函数定义。
x => x * x // x => x * x 箭头函数相当于 function (x) { return x * x; }
箭头函数有两种格式,一种如上,只包含一个表达式,和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略
{ ... }和
return
// 单个参数 x => { if (x > 0) { return x * x; } else { return - x * x; } } /* 如果参数不是一个需要用括号()括起来 */ // 两个参数: (x, y) => x * x + y * y // 无参数: () => 3.14 // 可变参数: (x, y, ...rest) => { var i, sum = x + y; for (i=0; i<rest.length; i++) { sum += rest[i]; } return sum; }
链式
形式上通过点的方式连续使用方法,如果你使用过Java中的StringBuilder那么你会很熟悉,JS也一样如果上一个方法有对象this的返回,就可以继续往下直接调用,可以简化中间临时变量或对象声明,还是举个例子,以下实现二维数组打印,其中只打印内部长度大于2的每一项。
const array1 = [ ['a','b','c'], ['d','e'] ]; array1.filter(item => item.length > 2).forEach(initem => console.log(initem)) // 输出 > Array ["a", "b", "c"]
本篇总结和分享先讲这些,后续还会有类似零散的但对测试开发编程有帮助的小总结,欢迎持续关注。
注解/参考
- javascript数组的方法总结,非常实用的!
- ES6学习总结之数组循环方法
- 学习总结之js循环数组的方法
- PHP循环遍历数组的3种方法list()、each()和while总结
- Javascript当中新增的几个实用操作数组的方法
- PHP循环遍历数组的3种方法list()、each()和while总结
- PHP循环遍历数组的3种方法list()、each()和while总结
- PHP循环遍历数组的3种方法list()、each()和while总结
- 工作总结 for 另类写法 循环加时间 集合合并 也是用的 static class Enumerable (IEnumerable<T>的扩展方法) (IEnumerable<T> 的 工具类) (所有集合 数组都实现IEnumerable<T>)
- js 数组最基础实用的方法总结
- PHP循环遍历数组的3种方法list()、each()和while总结
- 总结几个jsvaScript 数组排序方法
- java 循环方法总结
- 请高手指点,简单的几个数组操作方法不知道是否可以有更好的改进方法或者更简单的方法?
- 信息>后缀数组学习笔记--后缀数组解题方法总结
- JavaScript中的数组循环方法
- python数组遍历三种实用方法
- Javascript1.6数组新特性和jquery的几个工具方法
- 【C#基础知识】之结构、数组及常用的几种排序方法总结
- 复制数组方法总结