Array.prototype.map
一、map()概念
定义:map()创建一个新数组,其中的元素是原数组元素调用一个函数处理后的结果。
- 会按照原数组的顺序处理元素。
- 不会对空数组进行检测。
- “创建”,也就是说它不会改变原数组的内容。
- 处理数组时,数组元素的范围是在 callback 方法第一次调用之前确定。在 map()执行过程中:原数组中新增加的元素将不会被 callback 访问到;若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 map()遍历到它们的那一时刻的值;而被删除的元素将不会被访问到。
- 当不打算使用返回的新数组,或没有从回调函数中返回值时,不建议用map()。
- 没有办法中止或者跳出map() 循环,即不可用return、break。
- 使用箭头函数,thisArg 参数会被忽略。
二、语法
array.map(function(currentValue, index, arr), thisValue)
- currentValue: 必选,当前元素的的值。
- index: 可选,当前元素的索引.
- arr: 可选,当前元素所属的数组对象。
- thisValue: 可选,对象作为该执行回调时使用,传递给函数,用作 “this” 的值。如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
三、举个简单的栗子
var arr = [1,2,3,4,5];
var map01 = arr.map(x=>x*x);
console.log(map01); //(5) [1, 4, 9, 16, 25]
四、易错的例子
【MDN】map 方法中的 callback 函数只有一个参数是必需的,就是正在被遍历的当前数组元素本身。但这并不意味着 map 只给 callback 传了一个参数。这个思维惯性可能会让我们犯一个很容易犯的错误。看这个例子:
["1", "2", "3"].map(parseInt);
结果是[1,NaN,NaN],而不是[1,2,3]!!
这是因为parseInt函数是有两个参数的,第一个是要转为整数的表达式,第二个是转换的基数(一个在2~36范围内的数),而在这里第二个参数本来是回调函数中的index参数。
parseInt(string, radix) -> map(parseInt(value, index))
first iteration (index is 0): parseInt(“1”, 0); // 忽略0,结果:1
second iteration (index is 1): parseInt(“2”, 1); // 不可能有1进制,结果:NaN
third iteration (index is 2): parseInt(“3”, 2); // 二进制得不到3,结果:NaN
解决办法:
- 写一个在内部已经指定了parseInt方法转换进制的函数;
- 使用箭头函数语法,其实就是为parseInt()指定只有一个参数
['1', '2', '3'].map( str => parseInt(str) );
- 改为使用number(),但要注意二者的区别。
五、兼容旧环境
map被添加到第5版的ECMA-262标准中;因此,它可能不存在于标准的所有实现中。可以通过在脚本开头插入以下代码来解决此问题
查看MDN
Array.prototype.forEach()
一、概念
forEach() 方法对数组的每个元素执行一次提供的函数。
- 升序为数组中含有效值的每一项执行一次callback函数。
- 那些已删除或者未初始化的项将被跳过。
- 同样不会改变原数组的值(但是callback可能会改变原数组)。
- 总是返回 undefined 值,并且不可链式调用!
- 遍历的范围在第一次调用 callback 前就会确定。调用 forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()),之后的元素将被跳过。
- 没有办法中止或者跳出 forEach() 循环,即不可用return、break。
- 使用箭头函数,thisArg 参数会被忽略。
二、语法
array.forEach(callback(currentValue, index, array) {
// do something
}, thisArg)
参数含义与map()的相同
三、例子
来看一个迭代时被删除的例子:
var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
console.log(word);
if (word === 'two') {
words.shift();
}
});
// one two four
因为第二项被删除,后面的项都往前移了,three变成刚刚已经遍历过的索引为1的项,被跳过。
使用箭头函数的例子:
var arr = [1, 2, 3];
arr.forEach((v, i, arr) => { //或用 map
console.log(this);
}, arr)
// window
// window
// window
四、兼容旧版本
forEach 是在第五版本里被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,可以在调用 forEach 之前 插入下面的代码,在本地不支持的情况下使用 forEach()。该算法是 ECMA-262 第5版中指定的算法。查看MDN
map与forEach的区别
由上可以看到,它们基本上可以互换。最主要的区别在于,map()会分配内存空间存储新数组并返回,不会改变原来的数组,而forEach()不返回,但允许callback更改原始数组的元素。
Array.prototype.filter()
一、概念
定义:filter() 方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
- 返回一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。
- 不会改变原数组。
- 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。
二、语法[MDN]
var newArray = arr.filter(callback(element, index, array), thisArg)
- callback: 用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。
- element: 数组中当前正在处理的元素。
- index: 可选,正在处理的元素在数组中的索引。
- array: 可选,调用了 filter 的数组本身。
- thisArg: 可选,执行 callback 时,用于 this 的值。否则,callback 的 this 值在非严格模式下将是全局对象,严格模式下为 undefined。callback 函数最终观察到的 this 值是根据通常函数所看到的 "this"的规则确定的。
三、简单的例子
var f = [1, 2, 3, 4].filter(function(f) {
return f >= 3;
});
console.log(f);
// [3, 4]
四、兼容旧版本
filter 被添加到 ECMA-262 标准第 5 版中,因此在某些实现环境中不被支持。可以把下面的代码插入到脚本的开头来解决此问题,该代码允许在那些没有原生支持 filter 的实现环境中使用它。该算法是 ECMA-262 第 5 版中指定的算法。查询MDN
Array.prototype.some()&Array.prototype.every()
那顺便讲一下some()和every()吧hhh~
一、语法
array.some(function(currentValue,index,arr),thisValue)
array.every(function(currentValue,index,arr),thisValue)
同样也只有currentValue是必需的,含义参考以上方法的参数含义,很好理解啦。
二、概念
- 两个方法都返会布尔值。some()测试数组中是否存在某个元素符合回调函数,找到这个元素之后返回true,并且不会再继续测试之后的元素,否则返回false。every()测试数组中是否所有元素都符合回调函数,若找到一个元素不符合,则返回false,并且不再测试之后的元素,否则返回true。
- 两个方法都不会改变原数组。
- 两个方法都不会对空数组进行检测。
- 在es5时才被加入为标准,要考虑兼容问题(IE、firefox)