数组在javascript中使用度非常频繁,我总结了一些在数组中很常见的问题。
关于数组中的方法非常多,我总结了一张表来大致了解数组中的方法
Array中的方法 | 含义 | 改变原数组 | 返回值 | ES6新增 |
---|---|---|---|---|
concat | 合并两个或多个数组 | false | 新数组 | false |
copyWithin | 浅复制数组的一部分到同一数组中的另一个位置 | true | 改变后的数组 | true |
entries | 返回数组迭代器对象,该对象包含数组中每个索引的键/值对 | false | 数组迭代器 | true |
every | 测试数组的所有元素是否都通过了指定函数的测试 | false | 布尔值,true/false | false |
fill | 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素 | true | 改变后的数组 | true |
filter | 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素 | false | 新数组 | false |
find | 返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined | false | javascript语言类型 | true |
findIndex | 返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1 | false | 数组索引 | true |
forEach | 遍历数组 | false | undefined | false |
includes | 判断一个数组是否包含一个指定的值 | false | 布尔值,true/false | true |
indexOf | 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1 | false | 数组索引 | false |
join | 将数组(或一个类数组对象)的所有元素连接到一个字符串中 | false | 字符串 | false |
keys | Array迭代器,它包含数组中每个索引的键 | false | 数组迭代器 | true |
lastIndexOf | 返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1 | false | 数组索引 | false |
map | 遍历数组 | false | 新数组 | false |
pop | 从数组中删除最后一个元素,并返回该元素的值 | true | 数组元素 | false |
push | 将一个或多个元素添加到数组的末尾,并返回新数组的长度 | true | 数组长度 | false |
reduce | 对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值 | false | 函数返回值 | false |
reduceRight | reduce执行方向相反,从右到左 | false | 函数返回值 | false |
reverse | 将数组中元素的位置颠倒 | true | 改变后的数组 | false |
shift | 从数组中删除第一个元素,并返回该元素的值 | true | 数组元素 | false |
slice | 可从已有的数组中返回选定的元素 | false | 新数组 | false |
some | 测试数组中的某些元素是否通过由提供的函数实现的测试 | false | 布尔值,true/false | false |
sort | 在适当的位置对数组的元素进行排序 | true | 一个新数组 | false |
splice | 删除现有元素和/或添加新元素来更改一个数组的内容 | true | 删除的元素数组 | false |
toLocaleString | 返回一个字符串表示数组中的元素 | false | 字符串 | false |
toString | 返回一个字符串,表示指定的数组及其元素 | false | 字符串 | false |
unshift | 将一个或多个元素添加到数组的开头 | true | 数组长度 | false |
values | 一个数组迭代器对象,该对象包含数组每个索引的值 | false | 数组迭代器 | true |
从这个表中我们要小心几个方法,reverse和sort会改变原数组,并返回改变的新数组,push和unshift方法返回的是数组长度而不是数组,forEach方法返回的是undefined不是数组。
此外,我还需提一下slice和splice这两个方法,说实话这两个方法看起来很像,容易让人搞混,最关键的是用到的频率还蛮高的,这两个方法就像字符串中substr和substring这两个老兄弟,闲着没事就喜欢去迷惑别人,本人就曾深深的被这两个方法伤害过。
slice接受两个参数start和end,代表需要截取的数组的开始序号和结束序号。
var arr = [4,3,5,8,9,6];
arr.slice(0) // [4,3,5,8,9,6],end可以省略,默认为数组长度
arr.slice(0,4) //[4,3,5,8]
arr.slice(-1); //[6], start为负数代表从数组截取的开始序号从尾部算起
arr.slice(0,-1); //[4,3,5,8,9] end为负数表示结束序号从尾部算起
arr.slice(2,0); //[]
arr.slice(-1,-1); //[] 如果start和end符号相同,end一定大于start,否则返回的会是[]
splice的参数为index,deleteCount和...items,index表示需要删除或添加原数时的位置,负数表示从尾部算起,deleteCount表示要删除的元素,0表示不删除。其中items表示添加的元素个数。
var arr = [4,3,5,8,9,6];
arr.splice(0,0) //返回[], arr=[4,3,5,8,9,6];
arr.splice(0,2) //返回[4,3], arr=[5,8,9,6];
arr.splice(0,2,3,4) //返回[5,8], arr=[3,4,9,6];
splice不管是添加还是删除元素,返回的都是删除元素的列表,splice是先做删除操作,后添加
var arr = [4,3,5];
arr.splice(3,1,8,9); //返回[], arr= [4, 3, 5, 8, 9];
//如果index大于数组长度,那么splice不会删除元素
注意:虽然slice和splice都返回一个新的数组,但是slice不会改变原数组,splice会改变原数组,这个区别非常关键。
最后在加一些经常会问到的数组问题。
1.创建数组
//数组字面量创建
var arr = [1,2];
//Array构造器创建;
var arr = Array(1,2); //[1,2] 可以用new操作符,也可以不用
//Array构造器有个局限性,不能创建只有单个数字的数组
var arr = Array(10) //创建的是一个长度为10的空数组,并不是[10]
//如果传入的不是Number类型的数字,那么没有任何问题
var arr = Array('10') //['10']
//此时如果要创建只有单个数字的数组,可以用Array.of方法
var arr = Array.of(10) //[10]
var arr = Array.of(1,2) //[1,2]
//Array.from( items [ , mapfn [ , thisArg ] ] )
//items是个可迭代对象,mapfn是遍历该迭代对象的function,thisArg是mapfn中的this对象
var arr = Array.from([1,2,3]) //[1,2,3]
Array.from是非常有用的创建数组方法,能把字符串转化为数组,Map,Set也能转成数组。
Array.from('abc') //['a','b','c'];
Array.from(new Set([1,2,3])) //[1,2,3],当然这个例子毫无意义
Array.from(new Map([[1,2],[3,4]])) //[[1,2],[3,4]]
我们知道用Array构造器创建的数组是个空数组,map,forEach方法并不能遍历这个数组。
var arr = Array(10);
arr.forEach((item,index) => console.log(index)) //不会有输出
//map,forEach循环判断的是该对象上有没有对应的属性
arr.hasOwnProperty(0) //false,以hasOwnProperty为判断标准
//Array.from中的mapfn方法是以迭代方式来判断的,因此
Array.from(arr,(item,index)=>console.log(index)) //0,1,2,3,4,5,6,7,8,9
由于这个原因,我们可以快速对数组初始化,比如创建一个0到99的数组
Array.from(Array(100),(item,index)=>index);
//当然,如果你用到上表中Array的keys方法那更快捷
Array.from(Array(100).keys());
2.数组去重
方法一,创建对象的键值唯一性来进行去重:
var arr = [1,2,3,1,3,5,3,2];
var _arr = [];
var obj = {};
arr.forEach(item => {
if(!obj[item]){
_arr.push(item);
obj[item] = true;
}
})
arr = _arr;
方法二,结合Set的键值唯一性以及Array.from方法可以快速数组去重:
var arr = Array.from(new Set([1,2,3,1,3,5,3,2])) //[1,2,3,5]
3.快速复制一个数组
var arr = [1,2,3,4];
var arr1 = arr.slice();
var arr2 = arr.concat();
注:这里的复制指的是浅拷贝
4.求数组最大值,最小值
这里的数组指的是全是数字的数组
方法一,sort排序后取值
var arr = [1,4,6,2,33,19,6,9];
var maxvalue = arr.sort((a,b) => b>a )[0]
var minvalue = arr.sort((a,b) => a>b )[0]
方法二,Math的max和min方法调用
var arr = [1,4,6,2,33,19,6,9];
var maxvalue = Math.max.apply(null,arr); //33
var minvalue = Math.min.apply(null,arr); //1
5.数组排序
在不用系统自带的sort的情况下对数组排序有很多方法,比如冒泡、插入以及快速排序等。但我总觉得这些排序方法还是过于复杂,有没有更快以及更方便的排序,我思考了好久,后来先想到了可以用数组的序号进行排序。原理是把数组1中的值变成数组2中的序号:
var arr = [3,4,6,2,8,7,5],
arr2 = [];
arr.forEach(item => arr2[item] = item);
arr = [];
arr2.forEach(item => arr.push(item));
写完之后自己感觉美滋滋,可之后发现如果数组中有负数,不就都玩完了吗。于是赶紧改:
var arr = [3,-4,6,-2,-8,7,5],
parr = [];
narr = [];
arr.forEach(item => item>=0?parr[item] = item:narr[-item] = item);
arr = [];
parr.forEach(item => arr.push(item));
narr.forEach(item => arr.unshift(item));
注:如果数组中有重复数字则排序方法有误,会把重复数字去掉。
写完之后发现其实也没有比冒泡、插入以及快速排序的方法快多少。
6.求一个整数数组是否包含另一个整数数组
一开始我想到一个方法,把两个数组转换成字符串,在进行includes或者indexOf判断就可以了,后来我发现了问题:
var a = [2,4,8,6,12,67,9];
var b = [8,6,12];
a.join(',').includes(b.join(',')); //true; 这是可以的
var b = [8,6,1]
a.join(',').includes(b.join(',')); //true; 这居然也可以,显然有问题
//于是改成
a.join(',').includes(','+b.join(',')+','); //false;
//后来我又发现如果b数组在a数组的开头和结尾都会有问题,于是又改成如下:
(','+a.join(',')+',').includes(','+b.join(',')+','); //false;
写这篇文章主要是对自己学习数组做一个总结。如果对上面的问题有更好的解答,欢迎留言告知。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。