文章目录
-
-
- JavaScript 数组 Array
-
- 1)概述/前言
- 2)创建数组
-
- (一)Array()构造函数
- (二)数组字面量表示法
- (三)扩展操作符
- (四)工厂方法–Array.of()和Array.from
- 3)读写数组元素
- 4)数组长度
- 5)添加和删除数组元素
- 6)迭代数组
-
- for/of循环
- for/in循环
- forEach()方法
- 老式for循环(优化)
- 7)数组迭代器方法
-
- `forEach()`
- `map()`
- `filter()`
- `find()`与`findIndex()`
- `every()`与`some()`
- `reduce()`和`reduceRight()`
- 8)处理子函数的方法
-
- `slice()`
- `splice()`
- `fill()`
- `copyWithin()`
- 9)数组索引与排序方法
-
- indexOf()和lastIndexOf()
- `include()`
- `sort()`
-
JavaScript 数组 Array
1)概述/前言
与其他编程语言中的数组不同的是:
-
js数组是js中的一种特殊的(内置)对象,索引更像是属性名,只是刚好是整数。
-
在js中,数组是无类型限制的(即数组的元素可以是任意类型,包括自定义对象)。
-
ja数组是基于零且使用32位数值索引的(从最小0到最大2^32-2)
-
js数组是动态的
-
js数组可以是稀疏的(即元素不一定有连续的索引,中间可能有缝隙)
对于稀疏数组,length是大于所有元素的最高索引。
-
数组从Array.prototype继承属性,这个原型定义了很多数组操作方法。(并且很多都是泛型的)
-
ES6新增定型数组:
- 与常规js数组不同,定型数组具有固定长度和固定的数值元素类型
- 定型函数具有极高的性能
- 支持对二进制数据的字节级访问
下面将会从如何创建数组,一直到如何使用JS数组进行详细的介绍。(包含代码实例以及对一些易错易混的方法进行辨析),可以收藏以便不时之需。
2)创建数组
(一)Array()构造函数
var arr1 = new Array(); //创建空数组
var arr2 = new Array(20); //创建一个包含20项的数组
var arr3 = new Array(1,2,3) //包含三个数值的数组
(二)数组字面量表示法
var arr4 = []; //创建一个空数组
var arr5 = [20]; // 创建一个包含1项的数组
var arr6 = [1.1,true,"a",]; // 创建一个包含3个不同类型元素的数组
-
数组字面量中的值不需要是常量,可以是任意表达式
-
如果数组字面量中连续包含多个逗号,且逗号之间没有值,则这个数组为稀疏数组
let count = [1,,3]; //索引0和2有元素,索引1没有元素,但是按索引访问时返回undefined
-
数组字面量允许末尾出现逗号
因此
[ , ,]
的长度是2不是3
(三)扩展操作符
- 在一个数组字面量中包含另一个数组的元素
//扩展操作符
let a = [1,2,3];
let b = [0,...a,4];
console.log(b); //0,1,2,3,4,5
-
扩展操作符适用与任何可迭代对象(可以使用for/of循环遍历)
let digits = [..."0123456789"]; digits //=>["0","1",..."9:]
- 实例:
【数组 —> 集合 —> 数组】 实现数组的去重
集合对象是可迭代的,因此要去除数组中重复的元素,一种便捷的方式就是把数组转化为集合,然后再使用扩展操作符把这个集合转换回数组。
let letters = [..."hello world"]; //原数组 [...new Set(letters)] //=> ['h', 'e', 'l', 'o', ' ', 'w', 'r', 'd']
(四)工厂方法–Array.of()和Array.from
-
Array.of()
-
引入
在使用数值参数调用Array()构造函数时,这个参数指定的是数组的长度。
但是在使用一个以上的数值参数时,这些参数则会成为新数组的元素,这也就意味着使用Array()构造函数无法创建一个只包含一个特定数值元素的数组。
在ES6中,Array.of()函数可以解决这个问题
- Array.of()可以使用其参数值(无论多少个)作为数组元素来创建并返回新数组
Array.of(10) //=>[10],可以创建一个只有一个数组元素的数组 Array.of(1,2,3) //=>[1,2,3]
-
-
Array.from()
- 这个方法期待一个可迭代对象或类数组对象作为其第一个参数,并返回包含该对象元素的新数组。
Array.from()定义了一种给类数组对象创建真正的数组副本的机制,便于后续的操作
-
可以接受可选的第二个(函数)参数
那么在构建数组的时候,源对象的每个元素都会传入这个函数,这个函数的返回值将替代原始值成为新数组的元素(类似后面讲到的
map
方法,但是在构建数组期间执行映射的效率要高于构建完毕后再映射为另一个新数组)
3)读写数组元素
-
可以使用[ ] 操作符访问数组元素
-
JS数组是一个特殊对象,所有索引都是属性名。
-
与其他普通对象一样,JS会将数值数组索引转化为字符串(即1=>”1“)
-
可以使用负数或者非整数值来索引数组
此时,数值会转化为字符串,这个字符串会作为数组对象的属性名。
因此,JS数组没有所谓的越界说法。
-
4)数组长度
- 每个数组都有length属性
- 非稀疏数组的length属性就是数组中元素的个数
- 稀疏数组中length属性会大于数组元素的个数
- 改变length的值
- 变大:不会添加新元素,只会在数组末尾创建一个稀疏的区域
- 变小(为n):则任何索引>=n的元素都会从数组中删除
5)添加和删除数组元素
-
直接给新索引赋值
-
push()
方法-
在末尾添加一个或多个元素
-
与
push()
执行相反操作的是pop()
,它删除最后一个元素并返回该元素 -
类似地,
shift()
方法删除并返回数组的第一个元素 -
unshift()方法
实现将已有数组元素移动到更高索引位
-
-
delete
操作符使用delete删除数组元素
-
不影响数组长度
-
删除后变为稀疏数组,不会把高位索引向下移动来填充空隙
let a =[1,2,3]; delete a[2]; console.log(2 in a); //false console.log(a.length); //=>3:删除元素不影响数组长度,
-
-
splice()
方法
splice()是一个可以插入、删除或者替换数组元素的通用方法。
这个方法修改length属性并按照需要向更高位或更低位索引移动数组元素。
6)迭代数组
for/of循环
// for/of 输出list的所有元素
let list = [..."hello world"];
for (var item of list){
console.log(item);
}
如果 要对数组使用for /of 循环并且想知道每个元素的索引,可以使用数组的entries()方法和解构赋值
//[index,letter] of list.entries()
let list = [..."hello world"];
let everyother = "";
for (let [index,letter] of list.entries()){
//[index,letter]是每次循环解构赋值的对象
if (index % 2 === 0){
//取出奇数位字符
everyother += letter;
}
}
console.log(everyother); //=> hlowrd
for/in循环
//for in (索引) 输出list的所有元素
for (var i in list)
{
console.log(list[i]);
}
forEach()方法
//forEach() 用于自身迭代的函数式方法(需要传入一个函数作用于每个非空元素)
let list = [..."hello world"];
delete list[0]; //forEach能感知稀疏数组,不会空元素调用函数
let uppercase = "";
list.forEach(letter=>{
uppercase += letter.toUpperCase();
})
console.log(uppercase); //=> ELLO WORLD
老式for循环(优化)
当然,使用老式的for循环可以遍历数组。
在嵌套循环或是其他性能攸关的场合,推荐使用以下的两种for循环形式,只会读取一次数组长度,而不是在每个迭代中都读取一次。
//老式for循环
//(正向)把数组长度保存到局部变量中
for (let i=0,len = list.length;i<len;i++){
console.log(list[i]);
}
//反向
for (let i = list.length-1;i>=0;i--){
console.log(list[i]);
}
-
以上两个例子是假定数组是稠密的,即所有元素都包含有效数据
如果不是这个情况,那么可以在使用每个元素前进行测试:
//跳过稀疏部分 for (let i =0,len = list.length;i<len;i++){ if (list[i] === undefined) continue; console.log(list[i]); }
7)数组迭代器方法
下面介绍的方法用于迭代数组元素,他们会按顺序把数组的每个元素传给我们提供的函数,从而实现对数组的迭代、映射、过滤、测试和归并。
在这之前,先介绍这些方法的共同点:
-
所有方法都接受一个函数作为第一个参数,并且对数组的每个(或某些)元素都调用一次这个函数
-
这些方法都是可以感知稀疏数组的
-
通常情况下,我们提供的函数都会接受到3个参数,分别是
- 数组元素的值
- 数组元素的索引
- 数组本身
通常只需要这几个参数中的第一个,可以忽略第二和第三个的值。
forEach()
forEach()在调用我们指定的函数时会给他传3个参数:数组元素的值,数组元素的索引和数组本身。
如果只关心数组的值和索引,可以把函数写成接受两个参数的形式,忽略其他参数
//forEach()
let data = [1,2,3,4],sum=0;
//输出每个数组元素的下标以及对应的值
data.forEach((value,index)=>{
//接受数组的值和索引
console.log(`data[${
index}] = ${
value}`);
})
//输出如下:
//data[0] = 1
//data[1] = 2
//data[2] = 3
//data[3] = 4
【注意】:
- forEach()没有提供一种终止迭代的方式(也就是没有与常规break对等的语句)
- forEach()没有返回值
map()
map()方法把调用它的数组的元素传给我们指定的函数,返回这个函数的返回值构成的数组
例如:
//map
let a = [1,2,3];
let b= a.map(x=>x*x);
console.log(a);
console.log(b);
结果如下:
由此可见:
- map方法不改变原来数组的值
- 返回传入函数的返回值构成的数组。
filter()
filter方法返回一个数组。
该数组包含调用它的数组的子数组。传给它的函数应该是一个断言函数(返回true、flase)。
如果函数返回true,则传给这个函数的数组元素就是filter()最终返回的子数组的成员。实现过滤的效果:
例如:
//filter
let a = [5,4,3,2,1];
console.log(a.filter(x => x < 3)); //[2,1] : 返回的子数组元素为小于3的值
console.log(a.filter( (x,i) => i%2 === 0)); // [5,3,1] : 返回的子数组元素是索引为偶数的值
find()
与findIndex()
与filter()类似,表现为遍历数组,寻找断言函数返回真值的元素。
但是不同的是,这两个方法会在断言函数找到第一个元素时停止迭代。
此时,
- find返回匹配的元素
- findIndex返回匹配元素的索引。
如果没有找到匹配的元素:
- find返回undefined
- findIndex返回 -1
every()
与some()
传入这两个方法的函数也是断言函数,并且方法本身是数组断言方法(最后返回true或false)
-
every()方法类似于 “全称量词” —任意
它只在断言函数对数组的所有元素都返回true时every( )才返回true
//every() let a = [1,,2,3,4,5];z let every1 = a.every( x => x<10); console.log(every1); //true:所有元素都小于10 let every2 = a.every( x=> x%2 === 0); console.log(every2); //false: 不是所有元素都是偶数
-
some()方法类似于 “存在”量词—存在
只要有一个元素让断言函数返回true,some( )就返回true
//some() let a = [1,,2,3,4,5]; let some = a.some( x => x%2 === 0); console.log(some); //true: 数组a中包含偶数
【注意】:every()和some()都采取了短路求值的方式(即在他们知道要返回什么的时候停止迭代数组)
-
some()在遇到断言函数第一次返回true时就返回true,全部断言都返回false时才返回false
-
every()则相反,在遇到断言函数第一次遇到false时返回false,全部断言都返回true时才返回true
reduce()
和reduceRight()
reduce和reduceRight方法使用我们指定的函数来归并数组元素,最终产生一个返回值。
在函数编程中,归并时一个常见操作,有时候也称为“注入(inject)”或”折叠(fold)”
来看下面这个例子:
//reduce
let a = [1,2,3,4,5];
//求和
console.log( a.reduce((x,y)=> x+y , 0) ); // =>15 : 0 +1 +2 +3 +4 +5
//求积
console.log( a.reduce((x,y) => x*y ,1 )); //=>120 :1*1*2*3*4*5
//求最大值
console.log( a.reduce( (x,y)=>(x>y)?x:y)); //=>5 :最大值
【分析】:
reduce接受两个参数:
-
第一个是执行归并操作的函数
此时使用的函数与前面介绍的函数不同。我们熟悉的三个参数(值、索引、数组本身)在这里作为
第二、第三、第四个参数,而第一个参数是目前为止归并操作的累计结果
-
第二个参数是可选的,指定了归并操作的初始值(如从0开始累加,从1开始累乘)
- 如果传入了第二个参数,初次调用归并函数传入的参数是 ①初始值、 ②数组的第一个元素
- 如果省略了第二个参数,那么初次调用归并函数传入的参数则分别是数组的第一、第二个元素。
所以,在上面的求和、求积、求最大值的三个例子中,都可以不设定reduce()的第二个参数。
reduceRight()和reduce()类似,但是reduceRight是从高索引向低索引处理数组(从右到左)。
如果归并操作具有从右到左的结合性,那么可能就要用到reduceRight()
比如:
//reduceRight()
//计算2^(3^4)
let b = [2,3,4];
console.log( b.reduceRight( (exponent,base)=> Math.pow(base,exponent)) );
8)处理子函数的方法
下面再介绍几个数组的提取、替换、填充和复制切片的方法。
slice()
slice()方法返回一个数组的切片(slice)或者子数组。
接受2个参数: 分别是切片的起止位置
【注意】:
-
起止位置是左闭右开的一个区间(包含起始位置,不包含终止位置)
所以子数组的元素个数为两个参数的差(都为正数的情况下)
-
如果只指定一个参数,返回的是数组从起点到数组末尾的所有元素
-
如果两个参数有出现负数,则这个负值是相对于数组长度指定数组元素
比如参数-1指定数组的最后一个元素
-
slice()不会修改调用它的数组。
【例子】:
//slice()
let a = [1,2,3,4,5];
console.log( a.slice(0,3)); //=>[0,1,2]
console.log( a.slice(0)); //=>[1,2,3,4,5]
console.log( a.slice(1,-1)); // =>[2,3,4]
splice()
splice()是对数组进行插入和删除(可以同时执行)的通用方法。
与slice()不同,splice会修改调用它的数组。
-
删除元素
splice()的前两个参数确定要删除的元素
- 第一个参数指定要删除元素的起始位置
- 第二个参数指定从起始位置开始要删除元素的个数。
//splice() //删除数组元素 let a = [0,1,2,3,4,5]; a.splice(1,2); //从下标1开始删除2个元素:得到[0,3,4,5] console.log(a); //splice会改变调用它的数组
-
添加元素
slice()在前两个参数后面还能添加任意多个的参数,表示要在第一个参数指定的位置插入到数组中的元素
例如:
//splice() //同时在第一个参数指定的位置删除和添加元素 let a = [0,1,2,3,4,5]; a.splice(1,2,1,1,1); //从下标1开始删除2个元素:得到[0,1,1,1,3,4,5] console.log(a); //splice会改变调用它的数组
fill()
fill方法用于在指定位置上填充数组
它可以接受三个参数(其中后两个可选):
- 第一个参数设定要填充的值
- 第二个参数设定起始索引
- 第三个参数设定终止索引
省略参数和出现负数参数的情况的处理方式和slice()相同。
【例子】:
//fill()填充数组
let a = new Array(5); //创建一个长度为5的空数组
a.fill(0); //[0,0,0,0,0]
a.fill(9,1); //[0,9,9,9,9]
a.fill(8,2,-1) //[0,9,8,8,9]
copyWithin()
copyWithin()把数组切片复制到数组中的新位置。
它会就地修改并且返回修改后的数组,但是不会改变数组的长度。
- 接受三个参数(后面两个可选):
- 第一个参数指定复制到的目的索引
- 第二、第三个参数指定切片的范围(左闭右开)
- 省略参数和出现负数参数的情况的处理方式和slice()相同。
- copyWithin()方法本意是作为一个高性能的方法,尤其对定型数组特别有用。
- 即使来源和目标区域有重叠,复制也是正确的
//copyWithin()
let a = [1,2,3,4,5];
a.copyWithin(1); //[1,1,2,3,4]:把数组元素复制到索引1及之后(不改变数组长度前提下,所以5没有被复制过来)
console.log(a);
a.copyWithin(2,3,5); //[1,1,3,4,4]把最后两个元素复制到索引2
console.log(a);
9)数组索引与排序方法
数组实现与字符串的同名方法类似的indexof()
、lastIndexOf()
和includes()
方法,
此外还有sort()
和reverse()
方法用于对数组元素重新排序。
indexOf()和lastIndexOf()
这两个方法从数组中搜索指定的值并返回第一个找到的元素的索引。
如果没找到返回 -1.
区别在于:lastIndexOf是从后向前搜索数组。
//indexOf和lastIndexOf
let a =[0,1,2,1,0];
console.log(a.indexOf(1)); //从前向后找第一个:索引为1
console.log(a.lastIndexOf(1)); //从后向前找第一个:索引为3
console.log(a.indexOf(3)); //没找到,返回-1
此外,这两个方法还能接受第二个可选的参数,指定从哪个位置开始搜索。
//指定第二个参数
let a =[0,1,2,1,0];
console.log(a.lastIndexOf(1)); //从后向前找第一个:索引为3
console.log(a.indexOf(1,2)); //从索引2开始向后找第一个值位1的元素,返回它的索引:3
【注意】:字符串也有indexOf和lastIndexOf,区别在于字符串方法第二个参数如果是负数会被当成0。
include()
接受一个参数,如果数组包含该值则返回true,否则返回false。
它并不告诉你值的索引,只告诉你是否存在。
sort()
sort()方法对数组实现就地排序并返回排序后的数组。
在不传参调用时,sort默认按照字母顺序对数组元素排序。
//sort()
let a =["banana","cherry","apple"];
a.sort();
console.log(a); //["apple","banana","cherry"]
如果要实现按照非字母顺序排序,必须要给sort()传递一个比较函数作为参数,这个比较函数决定它的两个参数排序后的前后位置:
如果第一个参数要出现在前面,比较函数应该返回一个< 0 的值,反之要返回一个 >0的值。
如果两个值相等,则返回0。
//带函数的sort
//返回值<0时第一个参数在第二个参数前面
let a = [33,4,1111,222];
console.log(a.sort()); //[1111,222,33,4]
//升序 a<b (即a-b<0)
a.sort( function(a,b){
return a-b
})
console.log(a); //[4,33,222,1111]
//降序 a-b>0 即返回值b-a<0
a.sort( function(a,b){
return b-a;
});
console.log(a); //[1111,222,33,4]
reverse()
就地反转数组元素的顺序,并返回反序后的数组。
//reverse()
let a = [1,2,3];
console.log(a.reverse()); //[3,2,1]
🌊JS数组就介绍到这里啦!
💖💖J如果这篇文章对你有帮助的话希望三连下👍⭐✍支持一下博主🌊
💖💖如果有什么建议的话可以在评论区留言哦!或者私信博主而也可以哦!✍
今天的文章js …数组_JS 数组分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/58688.html