详解vue数组遍历方法forEach和map的原理解析和实际应用


Posted in Javascript onNovember 15, 2018

一、前言

forEach和map是数组的两个方法,作用都是遍历数组。在vue项目的处理数据中经常会用到,这里介绍一下两者的区别和具体用法示例。

二、代码

1. 相同点

  • 都是数组的方法
  • 都用来遍历数组
  • 两个函数都有4个参数:匿名函数中可传3个参数item(当前项), index(当前项的索引), arr(原数组),还有一个可选参数this
  • 匿名函数中的this默认是指向window的
  • 对空数组不会调用回调函数
  • 不会改变原数组(某些情况下可改变)

2. forEach

(1) 没有返回值。

var a = [1,2,3,4,5]
var b = a.forEach((item) => {
  item = item * 2
})
console.log(b)
// undefiined

(2) 可改变原数组的情况

下面来看几个例子:

var a = [1,2,3,4,5]
a.forEach((item) => {
  item = item * 2
})
console.log(a)
// [1,2,3,4,5]

这里原数组并没有发生改变。

var a = [1,'1',{num:1},true]
a.forEach((item, index, arr) => {
  item = 2
})
console.log(a)
// [1,'1',{num:1},true]

这里修改item的值,依然没有修改原数组。

var a = [1,'1',{num:1},true]
a.forEach((item, index, arr) => {
  item.num = 2
  item = 2
})
console.log(a)
// [1,'1',{num:2},true]

当修改数组中对象的某个属性时,发现属性改变了。

为什么会这样呢?

这里就要引入栈(stack)内存和堆(heap)内存的概念了,对于JS中的基本数据类型,如String,Number,Boolean,Undefined,Null是存在于栈内存中的,在栈内存中储存变量名及相应的值。而Object,Array,Function存在于堆内存中,在堆内存中储存变量名及引用位置。

在第一个例子中,为什么直接修改item无法修改原数组呢,因为item的值并不是相应的原数组中的值,而是重新建立的一个新变量,值和原数组相同。

在第二个例子中,数组中的对象的值也没有改变,是因为新创建的变量和原数组中的对象虽然指向同一个地址,但改变的是新变量的值,即新对象的值为2,原数组中的对象还是{num:1}。

在第三个例子中,由于对象是引用类型,新对象和旧对象指向的都是同一个地址,所以新对象把num变成了2,原数组中的对象也改变了。

var a = [1,2,3,4,5]
a.forEach((item, index, arr) => {
  arr[index] = item * 2
})
console.log(a)
// [2,4,6,8,10]

在回调函数里改变arr的值,原数组改变了。

这个例子和例三其实同理,参数中的arr也只是原数组的一个拷贝,如果修改数组中的某一项则原数组也改变因为指向同一引用地址,而如果给参数arr赋其他值,则原数组不变。

其实想要知道参数中的item和arr是不是重新创建的变量,在回调函数中打印就知道了。

(3) vue中的应用

在处理数据时我经常用到这个方法,因为数据的传递以json格式,经常会收到数组中包含许多对象的数据。而后端传给我的数据有时候需要处理,例如把时间戳格式化为正常时间,代码如下:

// utils.js
const formatTime = date => {
  var newDate = new Date();
  newDate.setTime(date * 1000);
  const year = newDate.getFullYear()
  const month = newDate.getMonth() + 1
  const day = newDate.getDate()
  const hour = newDate.getHours()
  const minute = newDate.getMinutes()
  const second = newDate.getSeconds()
 
  return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}

const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

export {
  formatTime
}
// 得到的数据格式
[
  {add_time: 1541495677, balance: 14, bn: "300708", cprice: "12.39"}
]
// index.vue
import axios from 'axios'
import { formatTime } from '@/lib/utils'
export default {
  data() {
    dataList: []
  },
  methods: {
    getData() {
     axios.get('/user?ID=12345')
     .then(function (res) {
       if(res.code == 200) {
        res.data.forEach((item) => {
          item.add_time = formatTime(item.add_time)
        }
        this.dataList = res.data
       }
     })
     .catch(function (err) {
      console.log(err);
     });
    }
  }
}

这时候原始数据的值也改变了,变成了格式化后的时间。

3. map

(1) 返回一个经过处理后的新数组,但不改变原数组的值。

var a = [1,2,3,4,5]
var b = a.map((item) => {
  return item = item * 2
})
console.log(a) // [1,2,3,4,5]
console.log(b) // [2,4,6,8,10]

(2) map中可改变原数组的情况和原理与forEach相同

(3) vue中的应用

有这样一个需求,充值金额需要在整数的基础上随机减去100或加上100,这时我在原始的数据基础上需要一个经过处理的新数组。

export default {
  data() {
    moneyList: [1000,2000,5000,10000,20000,50000]
  },
  computed: {
    moneyList_new() {
      return this.moneyList.map((item) => {
        const random = Math.random() > 0.5 ? 1 : -1;
        return Math.floor(Math.random()*100) * random + item;
      })
    }
  }
}

实际渲染处理过的数组就可以了~

三、结语

以上就是forEach和map的对比与实际应用,代码只是演示使用方法并非完全真实。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery jcrop插件截图使用方法
Nov 20 Javascript
通过伪协议解决父页面与iframe页面通信的问题
Apr 05 Javascript
js跨域请求的5中解决方式
Jul 02 Javascript
javascript封装 Cookie 应用接口
Aug 07 Javascript
如何给ss bash 写一个 WEB 端查看流量的页面
Mar 23 Javascript
关于Node.js的events.EventEmitter用法介绍
Apr 01 Javascript
dropload.js插件下拉刷新和上拉加载使用详解
Oct 20 Javascript
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
Feb 20 jQuery
vue基础之使用get、post、jsonp实现交互功能示例
Mar 12 Javascript
改进 JavaScript 和 Rust 的互操作性并深入认识 wasm-bindgen 组件
Jul 13 Javascript
深入分析jQuery.one() 函数
Jun 03 jQuery
基于JavaScript实现年月日三级联动
Jun 22 Javascript
微信小程序用户位置权限的获取方法(拒绝后提醒)
Nov 15 #Javascript
判断iOS、Android以及PC端的示例代码
Nov 15 #Javascript
IE8中jQuery.load()加载页面不显示的原因
Nov 15 #jQuery
详解ES6 Fetch API HTTP请求实用指南
Nov 14 #Javascript
微信小程序购物车、父子组件传值及calc的注意事项总结
Nov 14 #Javascript
微信小程序中遇到的iOS兼容性问题小结
Nov 14 #Javascript
javascript中一些奇葩的日期换算方法总结
Nov 14 #Javascript
You might like
留言板翻页的实现详解
2006/10/09 PHP
PHP+ajax 无刷新删除数据
2010/02/20 PHP
解析PHP中的正则表达式以及模式匹配
2013/06/19 PHP
php实现mysql数据库连接操作及用户管理
2015/11/08 PHP
PHP7新增运算符用法实例分析
2016/09/26 PHP
PHP编程获取各个时间段具体时间的方法
2017/05/26 PHP
短信提示使用 特效
2007/01/19 Javascript
用javascript实现的图片马赛克后显示并切换加文字功能
2007/04/21 Javascript
javascript静态页面传值的三种方法分享
2013/11/12 Javascript
构造函数+原型模式构造js自定义对象(最通用)
2014/05/12 Javascript
有关json_decode乱码及NULL的问题
2015/10/13 Javascript
jquery UI Datepicker时间控件的使用方法(加强版)
2015/11/07 Javascript
详解jQuery uploadify文件上传插件的使用方法
2016/12/16 Javascript
Bootstrap风格的zTree右键菜单
2017/02/17 Javascript
Vue.Js中的$watch()方法总结
2017/03/23 Javascript
Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的写法
2017/06/29 Javascript
动态加载权限管理模块中的Vue组件
2018/01/16 Javascript
vue中slot(插槽)的介绍与使用
2018/11/12 Javascript
Vue中props的详解
2019/05/16 Javascript
three.js利用卷积法如何实现物体描边效果
2019/11/27 Javascript
vuecli3.x中轻松4步带你使用tinymce的步骤
2020/06/25 Javascript
Python求导数的方法
2015/05/09 Python
Python网络爬虫与信息提取(实例讲解)
2017/08/29 Python
Python实用工具FuckIt.py介绍
2019/07/02 Python
python使用opencv对图像mask处理的方法
2019/07/05 Python
Python的缺点和劣势分析
2019/11/19 Python
Python3变量与基本数据类型用法实例分析
2020/02/14 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
Python高并发和多线程有什么关系
2020/11/14 Python
在购买印度民族服饰:Soch
2020/09/15 全球购物
简述使用ftp进行文件传输时的两种登录方式?它们的区别是什么?常用的ftp文件传输命令是什么?
2016/11/20 面试题
2014年学校工会工作总结
2014/12/06 职场文书
银行给客户的感谢信
2015/01/23 职场文书
2016猴年春节慰问信
2015/11/30 职场文书
高中物理教学反思
2016/02/19 职场文书
使用ICOM IC-R9500接收机同时测评十台收音机中波接收性能
2022/05/10 无线电