引言
JS数组前端开发应该经常与其打交道,尤其是在MVVM数据驱动视图,视图改变数据流行之后,开发网页多数时间在操作各种JS数组;那么它是什么?如何定义?有哪些属性?有哪些方法?如何遍历?
针对这些问题我在这里小结一下;
一、数组定义、特点、创建
定义:
- 数组是一组数据的集合,其表现形式就是内存中的一段连续的内存地址,数组名称其实就是连续内存地址的首地址
特点:
- 数组定义时可以无需指定数组长度
- 存储数据是无需指定具体类型,可以存储任意类型
创建:
- var array=[1,2,3]; // 隐式创建
- var array=new Array(1,2,3); //实例化创建
- var array=new Array(size);
二、数组属性
- length(经常用)
- constructor
- prototype: Array.prototype(prototype是一个指针指向一个原型对象);var array=new Array(size); array.proto=Array.prototype;
ps: JavaScript的prototype是仅函数拥有, 而对象也拥有prototype是源于其constructor属性所拥有的prototype.
三、数组方法
改变原数组的方法
pop()
删除数组最后一个元素,并返回该元素
push()
在数组尾部添加元素,并返回更新后的数组长度
shift()
删除数组的第一个元素,并返回该元素
unshift()
在数组第一位添加元素,并返回更新后的数组长度
reverse()
数组反转,返回反转之后数组
sort()
对数组排序(按字符ASCII进行排序),也可添加回调函数按照想要的规则排序,返回排序之后数组
splice(start,length,item)
删,增,替换数组元素,返回被删除数组,无删除则不返回
删除
替换
添加
fill(value, start, end)
使用一个固定值来替换数组中的元素。该固定值可以是字母、数字、字符串、数组等等。
不改变原数组的方法
concat()
连接多个数组,返回新的数组
join()
将数组中所有元素以参数作为分隔符放入一个字符
slice(start,end)
截取指定位置的数组,并返回截取的新数组
如果end没有则是从start到结尾,如果end为负数,则为(arr.length+end)的值.
toString()
直接转为字符串,并返回这个字符串
indexOf(value,index)
(从左往右)返回第一次出现元素的索引,没有找到就返回-1
lastIndexOf(value,index)
(从右往左)返回最后一次出现元素的索引,没有找到返回-1
5为查找的索引(也就是下标到5) 如数组里’q’,1,5, 4,4,'g’因为4在该索引里 所以打印4
indexOf是从前向后查 而lastIndexOf是从后向前查 但是二者返回索引都是从前开始数数和计算的
includes(value,index)
返回一个布尔值(ES7),表示某个数组是否包含给定的值,与字符串的includes方法类似。在没有它之前都是用IndexOf()判断;
indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于 -1 ,表达起来不够直观。二是,它内部使用严格相当运算符( === )进行判断,这会导致对NaN的误判。
[1, 2, NaN].includes(NaN); // true
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(3, -1); // true
find()
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。参数是回调函数。
findIndex()
返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。参数是回调函数。
四、数组遍历
数组自带遍历方法
forEach()
遍历数组中的每一项,没有返回值,对原数组没有影响,不支持IE
不能用break,return会报错;如果要return 可以用every和some代替;
map()
指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的新数组。
这种方式也是用的比较广泛的,虽然用起来比较优雅,但实际效率还比不上foreach
some()
对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。
都为false则为false,有一个是true则为true;
every()
是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true;有一个返回false则返回false;
filter()
“过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的新数组。
reduce()
从数组的第一项开始,逐个遍历到最后,迭代数组的所有项,然后构建一个最终返回的值。
reduce()接收一个或两个参数:第一个是回调函数,表示在数组的每一项上调用的函数;第二个参数(可选的)作为归并的初始值,被回调函数第一次执行时的第一个参数接收。 reduce(callback,initial);callback默认有四个参数,分别为prev,now,index,self。 callback返回的任何值都会作为下一次执行的第一个参数。 如果initial参数被省略,那么第一次迭代发生在数组的第二项上,因此callback的第一个参数是数组的第一项,第二个参数就是数组的第二项。
// 不省略initial参数,回调函数没有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
}, 2019)
// 打印结果为:
// 2019--10--0--true
// undefined--20--1--true
// undefined--30--2--true
// undefined--40--3--true
// undefined--50--4--true
// 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined
// 省略initial参数,回调函数没有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
})
// 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
// 10--20--1--true
// undefined--30--2--true
// undefined--40--3--true
// undefined--50--4--true
// 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined
// 不省略initial参数,回调函数有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
return "hello";
}, 2019)
// 打印结果为:
// 2019--10--0--true
// hello--20--1--true
// hello--30--2--true
// hello--40--3--true
// hello--50--4--true
// 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值
// 省略initial参数,回调函数有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
return "hello";
})
// 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
// 10--20--1--true
// hello--30--2--true
// hello--40--3--true
// hello--50--4--true
// 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值
// 省略initial参数,回调函数有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
return "hello";
})
// 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
// 10--20--1--true
// hello--30--2--true
// hello--40--3--true
// hello--50--4--true
// 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值
// 使用reduce计算数组中所有数据的和,initial参数
var arr = [10,20,45,90];
var sum = arr.reduce(function(prev,now,index,self){
console.log(prev+'---'+now);
return prev + now;
},8)
// 8---10
// 18---20
// 38---45
// 83---90
// 173
// 回调函数的最后一次return的结果被返回到reduce方法的身上
// 因为reduce有第二个参数initial,在第一次执行时被计算,所以最终结果被加上8
reduceRight()
(与reduce类似)从数组的最后一项开始,向前逐个遍历到第一位,迭代数组的所有项,然后构建一个最终返回的值。
entries(),keys()和values()
用于遍历数组。返回一个遍历器对象,可以用for…of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
其他数组遍历方法
for循环
使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。(其他循环都是for变形)
for(j = 0,len=arr.length; j < len; j++) {}
可以用break跳出循环,也可以用continue跳出本次循环;不能用return;
循环嵌套,外层为真内层执行,内层执行完毕外层继续执行;
for…of
遍历,不仅可以遍历数组,还可以遍历字符串,遍历类数组对象(通过entries(),keys()和values()返回的遍历器对象),支持 Map 和 Set 对象遍历;
解决了for循环的臃肿,继承了forEach()的简洁,补充了forEach不能使用 break 语句中断循环,也不能使用 return 语句返回到外层函数的不足。
let arr=[20,45,23,56,1,4]
for(let item of arr){
if(item===56){
break
}
console.log(item)
}
// 20
// 45
// 23
let arr=[20,45,23,56,1,4]
for(let item of arr){
if(item===56){
break
}
console.log(item)
}
// 20
// 45
// 23
for…in
遍历,主要遍历对象上的可枚举属性包括原型上的属性和方法。数组也算对象的一种,所以会遍历数组内所有可枚举的属性,包括原型上的属性和方法
for in更适合遍历对象,尽量不要使用for in 遍历数组
五、遍历总结
break
语句会使运行的程序立刻退出包含在最内层的循环或者退出一个switch语句。
for(),for…of,for…in,do…while(),while(),switch
continue
语句和break语句相似。所不同的是,它不是退出一个循环,而是开始循环的一次新迭代。
for(),for…of,for…in,do…while(),while(),switch
return
语句就是用于指定函数返回的值。return语句只能出现在函数体内,出现在代码中的其他任何地方造成语法错误!
map()返回新数组
filter()返回新数组
some(), every()返回boolean
reduce,reduceRight()返回构建最终值
六、数组相关方法
Array.from()
方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
- 部署了Iterator接口的对象,比如:Set,Map,Array。
- 类数组对象,什么叫类数组对象,就是一个对象必须有length属性,没有length,转出来的就是空数组。
1、array --> set (数组转set)
2、set --> array
Array.of()
方法用于将一组数值转换为数组,Array.of()基本上可以用来替代Array()或者new Array(),并且不存在由于参数个数的不同而导致的重载,它的行为非常统一。
const aaa = Array.of();
console.log(aaa); // []
const bbb = Array.of(1);
console.log(bbb); // [1]
const ccc = Array.of(1,2);
console.log(ccc); // [1,2]
const ddd = Array.of(undefined);
console.log(ddd); // [undefined]
Array()和Array.of()的区别
- Array()是构造方法。
a = new Array(1, 2, 3);
a = Array(1, 2, 3); // new可省略 - Array.of()是静态方法,也返回一个数组。
Array.of(…elements) 创建一个具有可变数量参数的新的数组实例。 - 如果只传入一个参数,且这个参数为Number数值类型。
new Array(3) 返回(4) [empty × 4],有3个空位empty的数组,长度为3。
Array.of(3) 依旧把唯一的数值参数作为元素,返回一个新数组,长度为1。