JavaScript 中 forEach、map、filter 详细

没有时间?直接看重点!

一、forEachmap 能实现的功能类似
二、forEachmapfilter 都能实现对原数组的修改
三、forEach 没有返回值,map 有返回值,filter 有返回值html


forEach

forEach() 方法对数组的每一个元素执行一次提供的函数。git

语法:github

array.forEach(callback(currentVal, index, array) {
  // do something
}, thisArg)
复制代码

forEach 使用说明

一、forEach 方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除(使用 delete 方法等状况)或者未初始化的项将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上)。数组

二、若是给 forEach 传递了 thisArg 参数,当调用时,它将被传给 callback 函数,做为它的 this 值。不然,将会传入 window 做为它的 this 值。callback 函数最终可观察到 this 值,这取决于 函数观察到 this 的经常使用规则。bash

关于 JavaScript 中的 this,我以为过重要了,须要仔细研读: neveryu.github.io/2018/06/01/…函数

三、forEach 遍历的范围在第一次调用 callback 前就会肯定。调用 forEach 后添加到数组中的项不会被 callback 访问到。若是已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。若是已访问的元素在迭代时被删除了(例如使用 shift()) ,以后的元素将被跳过。测试

四、forEach() 为每一个数组元素执行 callback 函数;不像 map() 或者 reduce() ,它老是返回 undefined 值,而且不可链式调用。典型用例是在一个链的最后执行反作用。ui

forEach 要点

一、没有返回值this

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

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

console.log(solt)	// undefined
复制代码

二、不能停止或跳出 forEach 循环spa

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
复制代码

三、使用箭头函数,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
复制代码

四、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() 不会在迭代以前建立数组的副本。

五、对原数组进行修改

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 使用说明

一、map 不修改调用它的原数组自己(固然能够在 callback 执行时改变原数组)。

二、若是 thisArg 参数有值,则每次 callback 函数被调用的时候,this 都会指向 thisArg 参数上的这个对象。若是省略了 thisArg 参数,或者赋值为 nullundefined,则 this 指向全局对象 。

三、map 方法会给原数组中的每一个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来造成一个新数组。 callback 函数只会在有值的索引上被调用;那些历来没被赋过值或者使用 delete 删除的索引则不会被调用。

四、使用 map 方法处理数组时,数组元素的范围是在 callback 方法第一次调用以前就已经肯定了。在 map 方法执行的过程当中:原数组中新增长的元素将不会被 callback 访问到;若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 map 方法遍历到它们的那一时刻的值;而被删除的元素将不会被访问到。【forEach 同样

map 要点

一、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 使用说明

一、filter 为数组中的每一个元素调用一次 callback 函数,并利用全部使得 callback 返回 true等价于 true 的值 的元素建立一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有经过 callback 测试的元素会被跳过,不会被包含在新数组中。

二、filter 不会改变原数组,它返回过滤后的新数组。

三、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