2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > JS中4种数组遍历方法( for forEach() for/in for/of)的区别

JS中4种数组遍历方法( for forEach() for/in for/of)的区别

时间:2018-09-08 05:53:49

相关推荐

JS中4种数组遍历方法( for  forEach()  for/in for/of)的区别

web前端|js教程

JavaScript,数组遍历

web前端-js教程

即时通信 源码,vscode安装视频,ubuntu去掉文件夹的高亮,tomcat配置jjvm,sqlite异常插入处理,java在线编辑word插件,前端框架排行,雨后出现的软体爬虫,php 统计数组,涟源seo培训,商城网站建设-,手机网页播放本地视频软件,安居客模板lzw

我们有多种方法来遍历 JavaScript 的数组或者对象,而它们之间的区别非常让人疑惑。Airbnb 编码风格禁止使用 for/in 与 for/of,你知道为什么吗?

华夏免费版探矿源码,二进制对比 vscode,6410 ubuntu,需要配置Tomcat运行环境,jsp sqlite项目,网页设计字体代码,网站服务器设置地点,距离插件2.41,几种简单前端框架,东营爬虫店,php鄙视,seo技术外包,springboot优雅事件,易语言制作网站yuanma,网页 登录 编程,html 打印模板,php后台搭建教程,jsp 页面视频播放器,商品销售管理系统 php,程序 小说lzw

这篇文章将详细介绍以下 4 种循环语法的区别:

房地产源码下载,ubuntu启动停在界面,tomcat7下哪个好,python爬虫 免登录,php怎么弹出提示框,seo招聘滨州lzw

for (let i = 0; i < arr.length; ++i)arr.forEach((v, i) => { /* ... */ })for (let i in arr)for (const v of arr)

语法

使用forfor/in,我们可以访问数组的下标,而不是实际的数组元素值:

for (let i = 0; i < arr.length; ++i) { console.log(arr[i]);}for (let i in arr) { console.log(arr[i]);}

使用for/of,则可以直接访问数组的元素值:

for (const v of arr) { console.log(v);}

使用forEach(),则可以同时访问数组的下标与元素值:

arr.forEach((v, i) => console.log(v));

非数字属性

JavaScript 的数组就是 Object,这就意味着我们可以给数组添加字符串属性:

const arr = ["a", "b", "c"];typeof arr; // objectarr.test = "bad"; // 添加非数字属性arr.test; // abcarr[1] === arr["1"]; // true, JavaScript数组只是特殊的Object

4 种循环语法,只有for/in不会忽略非数字属性:

const arr = ["a", "b", "c"];arr.test = "bad";for (let i in arr) { console.log(arr[i]); // 打印"a, b, c, bad"}

正因为如此,使用for/in遍历数组并不好。

其他 3 种循环语法,都会忽略非数字属性:

const arr = ["a", "b", "c"];arr.test = "abc";// 打印 "a, b, c"for (let i = 0; i console.log(i, el));// 打印 "a, b, c"for (const el of arr) { console.log(el);}

要点: 避免使用for/in来遍历数组,除非你真的要想要遍历非数字属性。可以使用 ESLint 的guard-for-in规则来禁止使用for/in

数组的空元素

JavaScript 数组可以有空元素。以下代码语法是正确的,且数组长度为 3:

const arr = ["a", , "c"];arr.length; // 3

让人更加不解的一点是,循环语句处理[a,, c][a, undefined, c]的方式并不相同。

对于[a,, c]for/inforEach会跳过空元素,而forfor/of则不会跳过。

// 打印"a, undefined, c"for (let i = 0; i console.log(v));// 打印"a, c"for (let i in arr) { console.log(arr[i]);}// 打印"a, undefined, c"for (const v of arr) { console.log(v);}

对于[a, undefined, c],4 种循环语法一致,打印的都是”a, undefined, c”。

还有一种添加空元素的方式:

// 等价于`[a, , c,, e]`const arr = ["a", "b", "c"];arr[5] = "e";

还有一点,JSON 也不支持空元素:

JSON.parse({"arr":["a","b","c"]});// { arr: [ a, , c ] }JSON.parse({"arr":["a",null,"c"]});// { arr: [ a, null, c ] }JSON.parse({"arr":["a",,"c"]});// SyntaxError: Unexpected token , in JSON at position 12

要点:for/inforEach会跳过空元素,数组中的空元素被称为”holes”。如果你想避免这个问题,可以考虑禁用forEach:

parserOptions: ecmaVersion: rules: no-restricted-syntax: - error - selector: CallExpression[callee.property.name="forEach"]message: Do not use `forEach()`, use `for/of` instead

函数的 this

forfor/infor/of会保留外部作用域的this

对于forEach, 除非使用箭头函数,它的回调函数的 this 将会变化。

使用 Node v11.8.0 测试下面的代码,结果如下:

"use strict";const arr = ["a"];arr.forEach(function() { console.log(this); // 打印undefined});arr.forEach(() => { console.log(this); // 打印{}});

要点: 使用 ESLint 的no-arrow-callback规则要求所有回调函数必须使用箭头函数。

Async/Await 与 Generators

还有一点,forEach()不能与 Async/Await 及 Generators 很好的”合作”。

不能在forEach回调函数中使用 await:

async function run() { const arr = [a, , c]; arr.forEach(el => { // SyntaxError await new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); });}

不能在forEach回调函数中使用 yield:

function run() { const arr = [a, , c]; arr.forEach(el => { // SyntaxError yield new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); });}

对于for/of来说,则没有这个问题:

async function asyncFn() { const arr = ["a", "b", "c"]; for (const el of arr) { await new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); }}function* generatorFn() { const arr = ["a", "b", "c"]; for (const el of arr) { yield new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); }}

当然,你如果将forEach()的回调函数定义为 async 函数就不会报错了,但是,如果你想让forEach按照顺序执行,则会比较头疼。

下面的代码会按照从大到小打印 0-9:

async function print(n) { // 打印0之前等待1秒,打印1之前等待0.9秒 await new Promise(resolve => setTimeout(() => resolve(), 1000 - n * 100)); console.log(n);}async function test() { [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(print);}test();

要点: 尽量不要在forEach中使用 aysnc/await 以及 generators。

结论

简单地说,for/of是遍历数组最可靠的方式,它比for循环简洁,并且没有for/inforEach()那么多奇怪的特例。for/of的缺点是我们取索引值不方便,而且不能这样链式调用forEach().forEach()

使用for/of获取数组索引,可以这样写:

for (const [i, v] of arr.entries()) { console.log(i, v);}

参考

For-each over an array in JavaScript?

Why is using “for…in” with array iteration a bad idea?

Array iteration and holes in JavaScrip

编程入门!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。