JavaScript 中 forEach、map、filter 詳細

NeverYu發表於2019-03-26

沒有時間?直接看重點!

1、forEachmap 能實現的功能相似
2、forEachmapfilter 都能實現對原陣列的修改
3、forEach 沒有返回值,map 有返回值,filter 有返回值


forEach

forEach() 方法對陣列的每個元素執行一次提供的函式。

語法:

array.forEach(callback(currentVal, index, array) {
  // do something
}, thisArg)
複製程式碼

forEach 使用說明

1、forEach 方法按升序為陣列中含有效值的每一項執行一次 callback 函式,那些已刪除(使用 delete 方法等情況)或者未初始化的項將被跳過(但不包括那些值為 undefined 的項)(例如在稀疏陣列上)。

2、如果給 forEach 傳遞了 thisArg 引數,當呼叫時,它將被傳給 callback 函式,作為它的 this 值。否則,將會傳入 window 作為它的 this 值。callback 函式最終可觀察到 this 值,這取決於 函式觀察到 this 的常用規則。

關於 JavaScript 中的 this,我覺得太重要了,需要仔細研讀: neveryu.github.io/2018/06/01/…

3、forEach 遍歷的範圍在第一次呼叫 callback 前就會確定。呼叫 forEach 後新增到陣列中的項不會被 callback 訪問到。如果已經存在的值被改變,則傳遞給 callback 的值是 forEach 遍歷到他們那一刻的值。已刪除的項不會被遍歷到。如果已訪問的元素在迭代時被刪除了(例如使用 shift()) ,之後的元素將被跳過。

4、forEach() 為每個陣列元素執行 callback 函式;不像 map() 或者 reduce() ,它總是返回 undefined 值,並且不可鏈式呼叫。典型用例是在一個鏈的最後執行副作用。

forEach 要點

1、沒有返回值

var arr1 = [1, 2, 3, 4, 5]

var solt = arr1.forEach((v,i,t) => {
  console.log(v)
})

console.log(solt)	// undefined
複製程式碼

2、不能中止或跳出 forEach 迴圈

var arr1 = [1, 2, 3, 4, 5]

// 使用break會報錯
arr1.forEach((v,i,arr) => {
  console.log(v)
  if(v === 3) {
    break
  }
})

// return false 也無效
arr1.forEach((v,i,arr) => {
  console.log(v)
  if(v === 3) {
    console.log('-----')
    return false
  }
})
// 1
// 2
// 3
// -----
// 4
// 5
複製程式碼

3、使用箭頭函式,thisArg 引數會被忽略

var arr1 = [1, 2, 3]
var arr2 = [7, 8, 9]

arr1.forEach((v, i, arr) => {
  console.log(this)
})
// window
// window
// window

arr1.forEach((v, i, arr) => {
  console.log(this)
}, arr2)
// window
// window
// window
複製程式碼

4、forEach()不會在迭代之前建立陣列的副本 如果陣列在迭代時被修改了,則其他元素會被跳過

var words = ["one", "two", "three", "four"];
words.forEach(function(word) {
  console.log(word);
  if (word === "two") {
    words.shift();
  }
});
// one
// two
// four
複製程式碼

當到達包含值 "two" 的項時,整個陣列的第一個項被移除了,這導致所有剩下的項上移一個位置。因為元素 "four" 現在在陣列更前的位置,"three" 會被跳過。 forEach() 不會在迭代之前建立陣列的副本。

5、對原陣列進行修改

var arr1 = [1, 2, 3]
var arr2 = [7, 8, 9]

arr1.forEach(function(v, i, arr) {
  console.log(this)
  arr[i] = v * 2
}, arr2)

console.log(arr1)
// (3) [7, 8, 9]
// (3) [7, 8, 9]
// (3) [7, 8, 9]
// (3) [2, 4, 6]
複製程式碼

arr1 從 [1, 2, 3] 變成了 [2, 4, 6] 函式內部 this 值是 arr2


map

map() 方法建立一個陣列,其結果是該陣列中的每個元素都呼叫一個提供的函式後返回的結果

語法:

let new_array = arr.map(function(v, i, arr) {
  // Return element for new_array 
}[, thisArg])
複製程式碼

返回值:

一個新陣列,每個元素都是回撥函式的結果
複製程式碼

map 使用說明

1、map 不修改呼叫它的原陣列本身(當然可以在 callback 執行時改變原陣列)。

2、如果 thisArg 引數有值,則每次 callback 函式被呼叫的時候,this 都會指向 thisArg 引數上的這個物件。如果省略了 thisArg 引數,或者賦值為 nullundefined,則 this 指向全域性物件 。

3、map 方法會給原陣列中的每個元素都按順序呼叫一次 callback 函式。callback 每次執行後的返回值(包括 undefined)組合起來形成一個新陣列。 callback 函式只會在有值的索引上被呼叫;那些從來沒被賦過值或者使用 delete 刪除的索引則不會被呼叫。

4、使用 map 方法處理陣列時,陣列元素的範圍是在 callback 方法第一次呼叫之前就已經確定了。在 map 方法執行的過程中:原陣列中新增加的元素將不會被 callback 訪問到;若已經存在的元素被改變或刪除了,則它們的傳遞到 callback 的值是 map 方法遍歷到它們的那一時刻的值;而被刪除的元素將不會被訪問到。【forEach 一樣

map 要點

1、querySelectorAll 應用

var elems = document.querySelectorAll('select option:checked');
var values = Array.prototype.map.call(elems, function(obj) {
  return obj.value
});
複製程式碼

上面程式碼展示瞭如何去遍歷用 querySelectorAl 得到的動態物件集合。在這裡,我們獲得了文件裡所有選中的選項,並將其列印。

map 使用技巧案例

通常情況下,map 方法中的 callback 函式只需要接受一個引數,就是正在被遍歷的陣列元素本身。但這並不意味著 map 只給 callback 傳了一個引數。這個思維慣性可能會讓我們犯一個很容易犯的錯誤。

// 下面的語句返回什麼呢:
["1", "2", "3"].map(parseInt);
// 你可能覺得會是 [1, 2, 3]
// 但實際的結果是 [1, NaN, NaN]
複製程式碼

通常使用 parseInt 時,只需要傳遞一個引數. 但實際上,parseInt 可以有兩個引數,第二個引數是進位制數. 可以通過語句 alert(parseInt.length) === 2 來驗證. map 方法在呼叫 callback 函式時,會給它傳遞三個引數:當前正在遍歷的元素,元素索引,原陣列本身. 第三個引數 parseInt 會忽視,但第二個引數不會,也就是說: parseInt 把傳過來的索引值當成進位制數來使用. 從而返回了 NaN.

或者可以使用箭頭函式:

['1', '2', '3'].map( str => {
  parseInt(str)
})
複製程式碼

一個更簡單的方式:

['1', '2', '3'].map(Number);  // [1, 2, 3]
// 與 parseInt 不同,下面的結果會返回浮點數或指數:
['1.1', '2.2e2', '3e300'].map(Number);  // [1.1, 220, 3e+300]
複製程式碼

filter

filter() 方法建立一個新陣列,其包含通過所提供函式實現的測試的所有元素

語法:

var new_array = arr.filter(callback[, thisArg])
複製程式碼

filter 使用說明

1、filter 為陣列中的每個元素呼叫一次 callback 函式,並利用所有使得 callback 返回 true等價於 true 的值 的元素建立一個新陣列。callback 只會在已經賦值的索引上被呼叫,對於那些已經被刪除或者從未被賦值的索引不會被呼叫。那些沒有通過 callback 測試的元素會被跳過,不會被包含在新陣列中。

2、filter 不會改變原陣列,它返回過濾後的新陣列。

3、filter 遍歷的元素範圍在第一次呼叫 callback 之前就已經確定了。在呼叫 filter 之後被新增到陣列中的元素不會被 filter 遍歷到。如果已經存在的元素被改變了,則他們傳入 callback 的值是 filter 遍歷到它們那一刻的值。被刪除或從來未被賦值的元素不會被遍歷到。

filter 示例

var filtered = [12, 5, 8, 130, 44].filter(function(v) {
  return v >= 10
})
// [12, 130, 44]
複製程式碼

寫在最後

我的主頁: neveryu.github.io/index.html

QQ群:685486827

JavaScript 中 forEach、map、filter 詳細

相關文章