博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js中的数组遍历for forEach for of之间的区别
阅读量:6039 次
发布时间:2019-06-20

本文共 2562 字,大约阅读时间需要 8 分钟。

遍历数组并对数组的每一项进行操作,常用的方法有for循环,forEach,for of,它们各自有什么区别,分别适用于什么时候,这是本文要讨论的。

for循环

const arr = [1,2,3,null,4,5]//普通的for循环for (let i = 0; i < arr.length; i++) {    console.log(arr[i])}// 传说中性能较高的for循环for (let i = 0; len = arr.length; i < len; i++) {    console.log(arr[i])}复制代码

其实第二种for循环在chrome浏览器中的表现并不像人们说的不用每次取长度值,提高了效率。而实际运行结果和普通的for循环没有太大区别,因为v8引擎对对象属性操作做了很大的优化,length做为数组的属性,并不需要每次都重新计算数组的长度。

forEach

mdn描述:forEach 方法按升序为数组中含有效值的每一项执行一次callback 函数,那些已删除或者未初始化的项将被跳过。

语法:arr.forEach(callback[, thisArg]), 返回值: undefined

  1. 将for循环改写为forEach
arr.forEach((item) => {    console.log(item)})复制代码

可以看出对比for循环,forEach不用去维护一个索引值,但是forEach也有缺点:没有办法跳出forEach循环

  1. 不建议在forEach中操作数组,因为结果可能不符合你的预期
var a = [1, 2, 3, 1, 2, 3];a.forEach((item, index) => {    console.log(index, item);    if (item === 1) {    	a.splice(index, 1);    }});// 输出// 0 1// 1 3// 2 1// 3 3var a = [1, 2, 3, 1, 2, 3];a.forEach((item, index) => {    console.log(index, item);    if (item === 1) {    	a.push(1);    }});// 输出// 0 1// 1 2// 2 3// 3 1// 4 2// 5 3复制代码

为什么第一个输出4次,第二个输出不是8次呢? 答案可以在mdn中找到: forEach 遍历的范围在第一次调用 callback 前就会确定。调用 forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()),之后的元素将被跳过。

  1. 模拟实现forEach
if (!Array.prototype.forEach) {  Array.prototype.forEach = function (callback, thisArgs) {    // forEach 遍历的范围在第一次调用 callback 前就会确定    const originData = this;    const l = originData.length;    for (let i = 0; i < l; i++) {    // 删除之后的元素会被跳过      if (this[i]) {        thisArgs ? callback.call(thisArgs, this[i], i, originData) : callback(this[i], i, originData);      }    }  }}复制代码

for of

为了减小多重循环的复杂度,es6提供了可迭代对象和for of循环共同解决这个问题

  1. 可迭代对象:

js中一些内置类型都是内置的可迭代类型并且有默认的迭代行为, 比如 Array or Map, 另一些类型则不是 (比如Object) 。如果普通对象想要成为可迭代对象必须实现@@iterator方法,意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有一个名字是 Symbol.iterator 的属性。这个属性会在for of循环的每一次迭代中被调用,这个函数返回一个迭代器

  • 内置的可迭代类型的prototype上有Symbol(Symbol.iterator)属性
Object.getOwnPropertySymbols(Map.prototype) //[Symbol(Symbol.toStringTag), Symbol(Symbol.iterator)]Object.getOwnPropertySymbols(Array.prototype) //[Symbol(Symbol.iterator), Symbol(Symbol.unscopables)]复制代码
  • 普通对象转化为可迭代对象
function *gen() {  yield 1;  yield 2;}const iterator = gen();var obj = {  a: 1}obj[Symbol.iterator] = function() {  return iterator}for (let item of obj) {  console.log(item);}// 1, 2复制代码

可以发现for of实际上是遍历的对象的Symbol.iterator属性

  1. for of循环的适用场景
  • 它扩展了迭代循环的应用对象,包括:数组,Set/Map,类数组对象,如 arguments 对象、DOM NodeList 对象,Generator 对象,字符串
  • 适用于只需要遍历对象中的元素
  • 在性能方面的优势:可以随时跳出

参考:

转载于:https://juejin.im/post/5ca1d186e51d451c8707184a

你可能感兴趣的文章
gulp压缩合并js与css
查看>>
块级、内联、内联块级
查看>>
Predicate
查看>>
[面试题记录01]实现一个function sum达到一下目的
查看>>
这个季节的忧伤,点到为止
查看>>
mysql通过配置文件进行优化
查看>>
省级网站群建设关注点
查看>>
工作第四天之采集资源
查看>>
我的友情链接
查看>>
H3CS-WLAN、H3CSE-Security认证考试
查看>>
5.0中redis-cli的集群管理测试
查看>>
TFS 2012研发管理能力(5)
查看>>
四种LaunchMode及其使用场景
查看>>
通过vbs脚本备份数据-本地到异地
查看>>
tomcat介绍和安装
查看>>
UIButton的titleLabel不同状态字体判断
查看>>
我的友情链接
查看>>
杨泽业:wordpress在Nginx/Apache/IIS中的伪静态规则
查看>>
Python 中使用 MongoDB 存储爬虫数据
查看>>
WindowsServer 2008 AD搭建FTP隔离用户
查看>>