JavaScript 数组原生方法集合
数组应该是我们在写程序中应用到最多的数据结构了,相比于无序的对象,有序的数组帮我们在处理数据时,实在是帮了太多的忙了。今天刚好看到一篇 Array.include 的文章,忽然发现经过几个 ES3,ES5,ES6,ES7 几个版本的更迭,发现在代码中用到了好多数组的方法,所以准备全部列出来,也是给自己加深印象。
1 ES3 中的数组方法
ES3 兼容现在所有主流浏览器
ES3 中的方法毫无疑问大家已经烂熟在心了,不过中间有些细节可以回顾加深一下记忆,比如是否修改原数组返回新数组,执行方法之后的返回值是什么,某些参数的意义是否搞混等等。熟悉的的可以直接快速浏览或者跳过。
1.1 join() 方法
Array.join() 方法是将一个数组里面的所有元素转换成字符串,然后再将他们连接起来 返回一个新数组 。可以传入一个可选的字符串来分隔结果字符串中的所有元素。如果没有指定分隔字符串,就默认使用逗号分隔。
let a = [1,2,3,4,5,6,7];
let b = a.join(); // b = "1,2,3,4,5,6,7";
let c = a.a.join(" "); // b = "1 2 3 4 5 6 7";
方法 Array.join() 恰好与 String.split() 相反,后者是通过将一个字符串分隔成几个元素来创建数组
1.2 reverse() 方法
Array.reverse() 方法将颠倒数组中元素的顺序并返回一个颠倒后的数组。 它在原数组上执行这一操作,所以说并不是创建了一个新数组 ,而是在已存在的数组中对元素进行重排。
let a = [1,2,3,4,5,6,7];
a.reverse(); // a = [7,6,5,4,3,2,1]
1.3 sort() 方法
Array.sort() 是在 原数组上进行排序 ,返回排序后的数组。如果调用方法时不传入参数,那么它将按照字母顺序对数组元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
如果数组中有未定义的元素,这些元素将放在数组的末尾
let a = [1,12,23,14,,undefined,null,NaN,56,6,7,"a",{},[]];
a.sort(); //[[], 1, 12, 14, 23, 56, 6, 7, "NaN", {}, "a", null,undefined,undefined × 1]
//返回的 NaN 已经是一个字符串,说明在比较过程中将其转化成了字符串进行比较
仔细看可以发现,上面顺序并没有按照数字大小进行排序。如果想按照其他标准进行排序,就需要提供比较函数。该函数比较前后两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
- 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
- 若 a 等于 b,则返回 0。
- 若 a 大于 b,在排序后的数组中 a 应该出现在 b 之后,则返回一个大于 0 的值。
let a = [1,12,23,14,,undefined,null,NaN,56,6,7,"a",{},[]];
a.sort((a,b) => {return a - b}); //[null, Array(0), NaN, Object, 1, 6, 7, 12, 14, 23, 56, "a",undefined, undefined × 1]
1.4 concat() 方法
Array.concat() 方法用于连接两个或多个参数(数组,字符串等), 该方法不会改变现有的数组,而会返回连接多个参数的一个新数组 。如果传入的参数是数组,那么它将被展开,将元素添加到返回的数组中。但要注意, concat 并不能递归的展开一个元素为数组的参数。
let a = [1,2,3];
let b = a.concat(4,5,[6,7,[9,10]]); // b = [1,2,3,4,5,6,7,[9,10]]];
1.5 slice() 方法
Array.slice() 方法可从已有的数组中返回指定的一个片段(slice),或者说是子数组。 它是从原数组中截取了一个片段,并返回到了一个新数组 。
Array.slice(a,b) 它有两个参数 a,b
参数 | 描述 |
---|---|
a | 必选 。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。 |
b | 可选 。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。 |
let a = [1,2,3,4,5,7,8];
let b = a.slice(3); // [4, 5, 7, 8]
let c = a.slice(3,5); // [4, 5]
let d = a.slice(-5,-2); // [3, 4, 5]
let d = a.slice(2,1); // []
请注意,该方法并不会修改数组,而是返回一个新的子数组。如果想删除数组中的一段元素,应该使用下面这个方法 Array.splice()。
1.6 splice() 方法
Array.splice() 方法从数组中添加/删除元素,然后 返回被删除的元素 。 它在原数组上修改数组 ,并不像 slice 和 concat 那样创建新数组。注意,虽然 splice 和 slice 名字非常相似,但是执行的却是完全不同的操作。
参数 | 描述 |
---|---|
index | 必选,整数 。规定添加/删除项目的位置,使用负数可从数组结尾处倒着寻找位置。 |
howmany | 可选,整数 。要删除的元素数量。如果设置为 0,则不会删除元素。如果没有选择,则默认从 index 开始到数组结束的所有元素 |
item1, ..., itemX | 可选 。向数组添加新的元素。 |
let a = [1,2,3,4,5,7,8];
let b = a.splice(3); // a = [1,2,3] b = [4, 5, 7, 8]
-----------------------------------------------------------
let c = [1,2,3,4,5,7,8];
let d = c.splice(3,5); // c = [1,2] d = [3,4,5,7,8]
-----------------------------------------------------------
let e = [1,2,3,4,5,7,8];
let f = e.splice(3,2,111,222,[1,2]); // e = [1, 2, 3, 111, 222,[1,2], 7, 8] f = [4,5]
大家要记住 slice() 和 splice() 两个方法第二个参数代表的意义是不一样的 。虽然这很基础,可是有时候还是会弄混。
1.7 push() 和 pop() 方法
Array.push() 方法可向数组的末尾添加一个或多个元素,并 返回新的长度 。
Array.pop() 方法用于删除并 返回数组的最后一个元素 。如果数组已经为空,则 pop() 不改变数组,并返回 undefined 值。
let a = [1,2,3,4,5];
let b = a.pop(); //a = [1,2,3,4] b = 5
let c = a.push(1,3,5); // a = [1,2,3,4,1,3,5] c = 7
上面两个方法都是直接对原数组进行操作。通过上面两个方法可以实现一个先进后出的栈。
1.8 unshift 和 shift() 方法
unshift,shift() 的方法行为和 push(),pop() 非常相似,只不过他们是对数组的头部元素进行插入和删除。
Array.unshift() 方法可向数组的头部添加一个或多个元素,并 返回新的长度 。
Array.shift() 方法用于删除并 返回数组的第一个元素 。如果数组已经为空,则 pop() 不改变数组,并返回 undefined 值。
let a = [1,2,3,4,5];
let b = a.shift(); //a = [2,3,4,5] b = 1
let c = a.unshift(1,3,5); // a = [1,3,5,2,3,45] c = 7
1.9 toString() 和 toLocaleString() 方法
和所有 javascript 的对象一样,数组也有 toString() 方法,这个方法可以将数组的每一个元素转化成字符串(如果必要的话,就调用元素的 toString() 方法),然后输出字符串的列表,字符串之间用逗号隔开。(用我的话来理解,其实就是遍历数组元素调用每个元素自身的 toString() 方法,然后用逗号连接)
toString() 的返回值和没有参数的 join() 方法返回的字符串相同
let a = let e = [1,undefined,null,Boolean,{},[],function(){console.log(1);}];
let b = a.toString(); // b = "1,,,function Boolean() { [native code] },[object Object],,function (){console.log(1);}"
注意,输出的结果中,返回的数组值周围没有括号。
toLocaleString 方法是 toString() 方法的 本地化版本 。它是使用地区特定的分隔符把生成的字符串连接起来,形成一个字符串。
虽然是两个方法,但是一般元素两个方法的输出结果却基本是一样的,去网上找了相关文章,发现只有两种情况比较有区分,一个是时间,一个是 4 位数字以上的数字,举例如下
let a = 1111;
let b = a.toLocaleString(); // b = "1,111"
let c = a.toString(); // c = "1111";
-------------------------------------------------------
let date = new Date();
let d = date.toString(); // d = "Sun Sep 03 2017 21:52:18 GMT+0800 (中国标准时间)"
let e = date.toLocaleString(); //e = "2017/9/3 下午 9:52:18"
好吧,这个 api 和数组关系不大。。。主要还是和数组中元素自身有关。啊哈哈,尴尬。
1.10 valueOf()
Array.valueOf() 方法在日常中用的比较少,该方法继承与 Object。javascript 中许多内置对象都针对自身重写了该方法,数组 Array.valueOf() 直接返回自身。
let a = [1,"1",{},[]];
let b = a.valueOf();
a === b; // true
好啦,关于 ES3 的方法就不详细描述了,我相信大家基本上都已经完全是烂熟于心的那种,唯一可能需要加强记忆的就是一些参数含义,返回数据这些了。
2 ES5 中的数组方法
- ES5 中的数组方法在各大浏览器的兼容性
- Opera 11+
- Firefox 3.6+
- Safari 5+
- Chrome 8+
- Internet Explorer 9+
2.Array 在 ES5 新增的方法中接受两个参数,第一个参数都是 function 类型,必选,默认有传参,这些参数分别是:
- currentValue : 数组当前项的值
- index : 数组当前项的索引
- array : 数组对象本身
第二个参数是当执行回调函数时指向的 this(参考对象),不提供默认为 window,严格模式下为 undefined。
以 forEach 举例
语法
array.forEach(callback, thisArg)
array.forEach(callback(currentValue, index, array){
//do something
}, thisArg)
例子:
//demo,注意 this 指向
//我这个 demo 没有用箭头函数来测试
let a = ['a', 'b', 'c'];
a.forEach(function(currentValue, index, array){
this.info(currentValue, index, array);
},{info:function(value,index,array){
console.log(`当前值${value},下标${index},数组${array}`)}
});
function info(value,index,array){
console.log(`外放方法 : 当前值${value},下标${index},数组${array}`)}
}
// 当前值 a,下标 0,数组 a,b,c
// 当前值 b,下标 1,数组 a,b,c
// 当前值 c,下标 2,数组 a,b,c
3.ES5 中的所有关于遍历的方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些 已删除(使用 delete 方法等情况)或者未初始化的项 将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上)。
例子:数组哪些项被跳过了
function logArrayElements(element, index, array) {
console.log(`a[${index}] = ${element}`);
}
let xxx; //定义未赋值
let a = [1,2,"", ,undefined,xxx,3];
delete a[1]; // 移除 2
a.forEach(logArrayElements);
// a[0] = 1
// 注意索引 1 被跳过了,因为在数组的这个位置没有项 被删除了
// a[2] = ""
// 注意索引 3 被跳过了,因为在数组的这个位置没有项,可以理解成没有被初始化
// a[4] = undefined
// a[5] = undefined
// a[6] = 3
好了,上面 3 点基本上是 ES5 中所有方法的共性,下面就不重复述说了。开始正文解析每个方法的不同了
2.1 forEach()
Array.forEach() 为每个数组元素执行 callback 函数;不像 map() 或者 reduce() , 它总是返回 undefined 值 ,并且不可链式调用。典型用例是在一个链的最后执行副作用。
注意: 没有办法中止或者跳出 forEach 循环,除了抛出一个异常。如果你需要跳出函数,推荐使用 Array.some。如果可以,新方法 find() 或者 findIndex() 也可被用于真值测试的提早终止。
例子:如果数组在迭代时被修改了
下面的例子输出"one", "two", "three"。当到达包含值"two"的项时,整个数组添加了一个项在第一位,这导致所有的元素下移一个位置。此时在下次执行回调中,因为元素 "two"符合条件,结果一直增加元素,直到遍历次数完毕。forEach() 不会在迭代之前创建数组的副本。
let a = ["one", "two", "three"];
let b = a.forEach((value,index,arr) => {
if (value === "two") {
a.unshift("zero");
}
return "new" + value
});
// one,0,["one", "two", "three"]
// two,1,["one", "two", "three"]
// two,2,["zero", "one", "two", "three"]
// two,3,["zero","zero", "one", "two", "three"]
看完例子可以发现,使用 forEach 方法处理数组时,数组元素的范围是在 callback 方法第一次调用之前就已经确定了。在 forEach 方法执行的过程中:原数组中新增加的元素将不会被 callback 访问到;若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 forEach 方法遍历到它们的那一个索引时的值。
ES5 中所有 API 在数组被修改时都遵从这个原则,以下不再重复
2.2 map()
Array.map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(没有指定返回值则返回 undefined)组合起来形成一个新数组。
例子:返回每个元素的平方根的数组
let a = [1,4,9];
let b = a.map((value) => {
return Math.sqrt(value); //如果没有 return,则默认返回 undefined
});
// b= [1,2,3]
2.3 filter()
Array.filter() 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中
例子:数组去重
let a = [1,2,3,4,32,6,79,0,1,1,8];
let b = a.filter((value,index,arr) => {
return arr.indexOf(value) === index;
});
// b = [1, 2, 3, 4, 32, 6, 79, 0, 8]
2.4 some()
Array.some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值, some 将会立即返回 true。否则,some 返回 false 。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。
例子:查看数组内是否含有大于 0 的元素
let a = [-1,4,9];
let b = a.some((value) => {
return value > 0; //如果没有 return,则默认返回 undefined,将无法告诉 some 判断
});
// b = true
some 方法可以理解成拥有跳出功能的 forEach() 函数,可以用在在一些需要中断函数的地方
2.5 every()
Array.every() 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。
例子:检测所有数组元素的大小,是否都大于 0
let a = [-1,4,9];
let b = a.every((value) => {
return value > 0; //如果没有 return,则默认返回 undefined
});
// b = false
2.6 indexOf()
Array.indexOf() 使用严格相等(strict equality,即===)进行判断 searchElement 与数组中包含的元素之间的关系。
Array.indexOf() 提供了两个参数,第一个 searchElement 代表要查询的元素,第二个代表 fromIndex 表示从哪个下标开始查找,默认为 0。
语法
arr.indexOf(searchElement)
arr.indexOf(searchElement, fromIndex = 0)
Array.indexOf() 会返回首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1
例子:
let array = [2, 5, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
2.7 lastIndexOf()
Array.lastIndexOf() 就不细说了,其实从名字大家也可以看出来,indexOf 是正向顺序查找,lastIndexOf 是反向从尾部开始查找,但是返回的 索引下标仍然是正向的顺序索引
。
语法
arr.lastIndexOf(searchElement, fromIndex = arr.length - 1)
需要注意的是,只是查找的方向相反,fromIndex 和返回的索引都是正向顺序的,千万不要搞混了(感觉我这么一说,大家可能搞混了,捂脸)。
例子:各种情况下的的 indexOf
var array = [2, 5, 9, 2];
var index = array.lastIndexOf(2); // index = 3
index = array.lastIndexOf(7); // index = -1
index = array.lastIndexOf(2, 3); // index = 3
index = array.lastIndexOf(2, 2); // index = 0
index = array.lastIndexOf(2, -2); // index = 0
index = array.lastIndexOf(2, -1); // index = 3
2.8 reduce()
Array.reduce() 为数组中的每一个元素依次执行回调函数,最后返回一个函数累计处理的结果。
语法
array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)
reduce 的回调函数中的参数与前面的不同,多了第一个参数,是上一次的返回值
- accumulator : 上一次调用回调返回的值,或者是提供的初始值(initialValue)
- currentValue : 数组当前项的值
- currentIndex : 数据当前项的索引。第一次遍历时,如果提供了 initialValue ,从 0 开始;否则从 1 开始
- array : 调用 reduce 的数组
- initialValue : 可选项,其值用于第一次调用 callback 的第一个参数。如果没有设置初始值,则将数组中的第一个元素作为初始值。 空数组调用 reduce 时没有设置初始值将会报错 。
例子:数组求和
let sum = [0, 1, 2, 3].reduce(function (o,n) {
return o + n;
});
// sum = 6
对了,当回调函数第一次执行时,accumulator 和 currentValue 的取值有两种情况:
- 调用 reduce 时提供 initialValue,accumulator 取值为 initialValue ,currentValue 取数组中的第一个值;
- 没有提供 initialValue ,accumulator 取数组中的第一个值,currentValue 取数组中的第二个值。
例子:reduce 数组去重
[1,2,3,4,5,6,78,4,3,2,21,1].reduce(function(accumulator,currentValue){
if(accumulator.indexOf(currentValue) > -1){
return accumulator;
}else{
accumulator.push(currentValue);
return accumulator;
}
},[])
注意 :如果数组为空并且没有提供 initialValue, 会抛出 TypeError 。如果数组仅有一个元素并且没有提供 initialValue, 或者有提供 initialValue 但是数组为空,那么此唯一值将被返回并且 callback 不会被执行。
2.9 reduceRight() 方法
Array.reduceRight() 为数组中的每一个元素依次执行回调函数,方向相反,从右到左,最后返回一个函数累计处理的结果。
因为这个方法和 reduce 方法基本是一模一样的,除了方法相反,所以就不详细的再写一遍了
2.10 isArray() 方法
之所以将这个方法放在最后,是因为这个方法和前面的不太一致,是用于确定传递的值是否是一个 Array,使用方法也很简单
例子
let a = Array.isArray([1,2,3]); //true
let b = Array.isArray(document.getElementsByTagName("body")); //类数组也为 false
不过感觉除非是临时判断,不然一般也不会用这个方法去判断,一般还是下面这种万金油型的吧。
Object.prototype.toString.call([]).slice(8, -1) === "Array";//true
好啦,关于 ES5 的方法基本上就讲到这里了,感觉自己在深入去看了一些文章之后,还是有一些额外的收获的。比如对 reduce 这个平时不常用的方法了解更加深刻了,感觉之前很多遍历收集数据的场景其实用 reduce 更加方便。
3 ES6 中的数组方法
不同于 es5 主要以遍历方法为主,es6 的方法是各式各样的,不过必须要说一句,在性能上,es6 的效率基本上是最低的。
3.1 ...方法——concat 方法的增强
英文名字叫做 Spread syntax,中文名字叫做扩展运算符。这个方法我不知道怎么描述,感觉更像是原有 concat() 方法的增强,可以配合着解构一起使用,大家还是直接看例子感受以下吧
例子:简单拷贝数组
//如果是 ES5
let c = [7,8,9].concat(a);
//如果是 ES6
let a = [1,23,4,5,6];
let b = [7,8,9,...a]; // b = [7, 8, 9, 1, 23, 4, 5, 6]
----------------------------------------------------------
//浅拷贝
let c = [{a : 1}];
let d = [...c]
d[0].a = 2
c[0].a // 2
可以看到这个方法对于引用类型仍然是浅复制,所以对于数组的深拷贝还是需要用额外的方法, 可以看我另外一篇文章
3.2 of() 方法
Array.of() 方法可以将传入参数以顺序的方式返回成一个新数组的元素。
let a = Array.of(1, 2, 3); // a = [1, 2, 3]
其实,刚看到这个 api 和他的用途,还是比较懵逼的,因为看上去这个方法就是直接将传入的参数变成一个数组之外,就没有任何区别了,那么我为什么不直接用以前的写法去实现类似的效果呢,比如 let = [1,2,3];而且看上去也更加直接。然后我去翻了下最新的 ECMAScript 草案,其中有这么一句话
The of function is an intentionally generic factory method; it does not require that its this value be the Array constructor. Therefore it can be transferred to or inherited by other constructors that may be called with a single numeric argument.
自己理解了一下,其实大概意思就是说为了弥补 Array 构造函数传入单个函数的不足,所以出了一个 of 这个更加通用的方法,举个例子
let a = new Array(1);//a = [undefined × 1]
let b = new Array(1,2);// b = [1,2]
大家可以注意到传入一个参数和传入两个参数的结果,完全是不一样的,这就很尴尬了。而为了避免这种尴尬,es6 则出了一种通用的 of 方法,不管你传入了几个参数,都是一种相同类型的输出结果。
不过我好奇的是,如果只传入几个参数,为什么不直接 let a = [1,2,3];效率和直观性也更加的高。如果要创建一个长度的数组,我肯定还是选 let a = new Array(10000),这种形式,实在没有感觉到 Array.of 的实用场景,希望大家可以给我点指导。
3.2 from() 方法
Array.from() 方法从一个类似数组(拥有一个 length 属性和若干索引属性的任意对象)或可迭代的对象(String, Array, Map, Set 和 Generator) 中创建一个新的数组实例。
我们先查看 Array.from() 的语法
语法
Array.from(arrayLike, mapFn, thisArg)
从语法中,我们可以看出 Array.from() 最基本的功能是将一个类数组的对象转化成数组,然后通过第二个和第三个参数可以对转化成功后的数组再次执行一次遍历数据 map 方法,也就是 Array.from(obj).map(mapFn, thisArg)。
对了额外说一句,这个方法的性能很差,和直接的 for 循环的性能对比了一下,差了百倍不止。
例子 :将一串数字字符串转化为数组
let a = Array.from("242365463432",(value) => return value * 2);
//a = [4, 8, 4, 6, 12, 10, 8, 12, 6, 8, 6, 4]
3.4 copyWithin() 方法
Array.copyWithin 方法,在当前数组内部,将指定位置的成员 浅复制 到其他位置(会覆盖原有成员),然后 返回当前数组 。也就是说,使用这个方法,会修改当前数组。
这个方法有点复杂,光看描述可能大家未必能轻易理解,大家可以先看下语法,再看 demo 配合理解,而且自己没有想到这个方法合适的应用场景。网上也没又看到相关使用场景。但是讲道理,这个方法设计出来,肯定是经过深思熟虑的,如果大家有想到,欢迎评论给我,谢谢。
语法
arr.copyWithin(target, start, end)
//arr.copyWithin(目标索引,源开始索引, 结束源索引)
例子
// 将 3-4 号位复制到 0 号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4); // [4, 2, 3, 4, 5]
// 将 2-5 号位复制到 0 号位
[1, 2, 3, 4, 5].copyWithin(0, 2, 5); //[3, 4, 5, 4, 5]
// 将 1-4 号位复制到 4 号位
[1, 2, 3, 4, 5].copyWithin(4, 1, 4); //[1, 2, 3, 4, 2]
复制遵循含头不含尾原则
第一个是常规的例子,大家可以对比看第二个可以发现,这个方法是先浅复制了数组一部分暂时存储起来,然后再从目标索引处开始一个个覆盖后面的元素,直到这段复制的数组片段全部粘贴完。
再看第三个例子,可以发现当复制的数据片段从目标索引开始粘贴时,如果超过了长度,它将停止粘贴,这说明 它不会改变数据的 length,但是会改变数据本身的内容 。
Array.copyWithin 可以理解成复制以及粘贴序列这两者是为一体的操作;即使复制和粘贴区域重叠,粘贴的序列也会有拷贝来的值。
3.5 find() 和 findIndex() 方法
Array.find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
Array.findIndex() 方法返回数组中满足提供的测试函数的第一个元素的值的索引。否则返回 -1。
这两个方法其实使用非常相似,使用场景有点像 ES5 中 Array.some,都是在找到第一个满足条件的时候,跳出循环,区别的是,三种返回的值完全不一样,我想这也许是为什么要在 ES6 中增加这两个 API 的原因吧,可以理解成是数组的方法的补足。
例子:三个方法各自的返回值
let a = [1,2,3,4,5].find((item)=>{return item > 3}); // a = 4 返回第一个符合结果的值
let b = [1,2,3,4,5].findIndex((item)=>{return item > 3}); // b = 3 返回第一个符合结果的下标
let c = [1,2,3,4,5].some((item)=>{return item > 3}); // c = true 返回是否有符合条件的 Boolean 值
-----------------不满足条件--------------------
let a = [1,2,3,4,5].find((item)=>{return item > 6}); // a = undefined
let b = [1,2,3,4,5].findIndex((item)=>{return item > 6}); // b = -1
let c = [1,2,3,4,5].some((item)=>{return item > 6}); // c = false
注意:find() 和 findIndex() 方法无法判断 NaN,可以说是内部用 ===判断,不同于 ES7 中的 include 方法。不过这个判断方式是另外一个话题,不在本文详述了,感兴趣的同学可以去查一下。
其实还可以发现,Array.find() 方法只是返回第一个符合条件的元素,它的增强版是 es5 中 Array.filter() 方法,返回所有符合条件的元素到一个新数组中。可以说是当用 find 方法时考虑跟多的是跳出吧。
我感觉这 4 个方法配合相应的回调函数基本上可以完全覆盖大多数需要数组判断的场景了,大家觉得呢?
3.5 fill 方法
Array.fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素, 返回原数组
这个方法的使用也非常简单,大家基本上看个语法和 demo 就能懂了。需要注意的是,这个方法是返回数组本身,还有一点就是,类数组不能调用这个方法,刚刚自己去改了 MDN 上面的文档。
语法
arr.fill(value)
arr.fill(value, startIndex)
arr.fill(value, startIndex, endIndex)
例子
let a = new Array(10);
a.fill(1); // a = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let b = [1,2,34,5,6,7,8].fill(3,4); //b = [1, 2, 34, 5, 3, 3, 3];
let c = [1,2,34,5,6,7,8].fill(3,2,5); // c = [1, 2, 3, 3, 3, 7, 8];
个人感觉这个方法初始化数组挺有用的,自己每次测试数据时,只要 new Array(10000).fill(1),比以前遍历直观方便多了
3.6 entries(),keys(),values() 方法
- Array.entries() 将数组转化成一个中包含 每个索引的键/值对 的 Array Iterator 对象
- Array.keys() 将数组转化成一个中包含 每个索引的键 的 Array Iterator 对象
- Array.values() 将数组转化成一个中包含 每个索引的值 的 Array Iterator 对象。
Array.values() 方法 chrome 浏览器并不支持
之所以将这三个方法放在一起是有原因的额,大家可以看这三个方法其实都是一个数组转化为一种新的数据类型——返回新的 Array Iterator 对象,唯一区别的是转化之后的元素不一样。跟他们的名字一样,entries() 方法转化为全部的键值对,key() 方法转化为键,value() 保留值。
例子:观察各个迭代器遍历输出的东西
Array.entries()
let a = [1,2,3].entries();
for(let i of a){console.log(i);}
//[0, 1]
//[1, 2]
//[2, 3]
Array.keys()
let b = [1,2,3].keys();
for(let i of b){console.log(i);}
//0
//1
//2
Array.values()
let c = [1,2,3].values();
for(let i of c){console.log(i);}
//1
//2
//3
关于迭代器这个东西,自己说不上什么,因为自己没有亲自用过,如果大家有什么见解课可以评论给我,我来补充和学习一下
4 ES7 中的数组方法
4.1 includes() 方法
Array.includes 方法返回一个布尔值,表示某个数组是否包含给定的值,如果包含,则返回 true,否则返回 false,与 字符串的 includes 方法 类似。
这个方法大家可以看作是 ES5 中 Array.indexOf 的语义增强版,includes 这个是否包含的意思,直接返回 Boolean 值,比起原来的 indexOf 是否大于-1,显得更加直观,我就是判断有没有包含哪个值
对了,Array.includes() 相比起 indexOf 这个方法还有一个增强之处是可以判断 NaN。
语法 ,使用方法和 indexof 一模一样
arr.includes(searchElement)
arr.includes(searchElement, fromIndex)
例子
let array = [2, 5, 9];
array.includes(2); // true
array.includes(7); // false
array.includes(9, 2); // true
array.includes(2, -1); // false
array.includes(2, -3); // true
[NaN].includes(NaN); // true
方法还真是 tmd 多啊,感觉基本上应该是更新完了,前后两星期花了我 4 天时间吧,还是挺累的。不过收货还是很多,比如知道了 ES5 的方法基本上都有第二个 this 指向的参数,重新认识了 reduce 方法,感觉自己之前很多场景用 reduce 更好,重新熟悉了一些 ES6 的方法可以试用有些场景。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 一般是怎么做代码重构的
下一篇: 不要相信一个熬夜的人说的每一句话
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论