1. 程式人生 > >vue 陣列遍歷方法forEach和map的原理解析和實際應用

vue 陣列遍歷方法forEach和map的原理解析和實際應用

一、前言

forEach和map是陣列的兩個方法,作用都是遍歷陣列。在vue專案的處理資料中經常會用到,這裡介紹一下兩者的區別和具體用法示例。

二、程式碼

1. 相同點

  1. 都是陣列的方法
  2. 都用來遍歷陣列
  3. 兩個函式都有4個引數:匿名函式中可傳3個引數item(當前項), index(當前項的索引), arr(原陣列),還有一個可選引數this
  4. 匿名函式中的this預設是指向window的
  5. 對空陣列不會呼叫回撥函式
  6. 不會改變原陣列(某些情況下可改變)

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的對比與實際應用,程式碼只是演示使用方法並非完全真實。

原文地址:https://segmentfault.com/a/1190000017011454