likes
comments
collection
share

一文掌握JavaScript 数组常用方法

作者站长头像
站长
· 阅读数 34

在JavaScript开发中,数组是经常使用的,特别是在前后端分离项目中,通过Ajax请求回来的响应中,数据列表即多条相同格式的数据,一般是返回的Array数组。那么掌握数组的方法,是我们前端开发的必备技能之一。

数组的方法按照其原理可分为以下几种:

迭代器方法用于遍历数组元素,通常会对每个元素调用一次我们指定的函数。

栈和队列方法用于在开头或末尾向数组中添加元素或从数组中删除元素。

子数组方法用于提取、删除、插入、填充和复制更大数组的连续区域。

搜索和排序方法用于在数组中查找元素和对数组元素排序。

数组到字符串的转换方法。

接下来,我们创建一个雇员的数组,用于演示数组的方法。

  let emp = [{
          empId: 1,
          empName: "刘德华",
          sex: 1,
          age: 30,
          money: 4000
        },
        {
          empId: 2,
          empName: "张学友",
          sex: 1,
          age: 34,
          money: 14500
        },
        {
          empId: 3,
          empName: "郭富城",
          sex: 0,
          age: 20,
          money: 2000
        },
        {
          empId: 4,
          empName: "黎明",
          sex: 0,
          age: 31,
          money: 3000
        }
      ]

迭代器方法

迭代器方法用于遍历数组元素,通常会对每个元素调用一次我们指定的函数。

forEach()

forEach()方法迭代数组的每个元素,并对每个元素都调用一次我们指定的函数。参数:数组元素的值、数组元素的索引和数组本身。

// 将每个雇员的工资+2000
emp.forEach((item, index, arr) => {
  item.money += 2000
})
console.log( emp); // => emp数组 
map()

map()方法把调用它的数组的每个元素分别传给我们指定的函数,返回这个函数的返回值构成的数组。

// 返回一个包含雇员姓名的新数组
let newEmp = emp.map((item,index) => {
  return item.empName
})
console.log(newEmp); // => ["刘德华", "张学友", "郭富城", "黎明"]
filter()

filter()方法返回一个数组,该数组包含调用它的数组的子数组。传给这个方法的函数应该是个断言函数,即返回true或false的函数。

// 过滤 sex值为1 的雇员 
let newEmp = emp.filter((item,index) => {
  return item.sex ==1
})
console.log(newEmp); // => (2) [{…}, {…}]
find()与findIndex()

find()和findIndex()方法与filter()类似,表现在它们都遍历数组,寻找断言函数返回真值的元素。但与filter()不同的是,这两个方法会在断言函数找到第一个元素时停止迭代。此时,find()返回匹配的元素,findIndex()返回匹配元素的索引。如果没有找到匹配的元素,则find()返回undefined,而findIndex()返回-1。

// 查找雇员姓名为黎明的对象元素
let find = emp.find((item,index) => {
  return item.empName == "黎明"
})
console.log(find); // => {empId: 4, empName: "黎明", sex: 0, age: 31, money: 3000}// 查找雇员姓名为黎明的对象元素
let findIndex = emp.findIndex((item,index) => {
  return item.empName == "黎明"
})
console.log(findIndex); // => 3
every()与some()

every()和some()方法是数组断言方法,即它们会对数组元素调用我们传入的断言函数,最后返回true或false。

every()方法与数学上的“全称”量词类似,它在且只在断言函数对数组的所有元素都返回true时才返回true。

// 只有所有对象元素都有此属性且值为黎明时,才返回ture,否则返回false
let every = emp.every((item,index) => {
  return item.empName == "黎明"
})
console.log(every); // => false// 只有所有对象元素的money大于100时,才返回ture,否则返回false
let everyMoney = emp.every((item,index) => {
  return item.money >100
})
console.log(everyMoney); // => false
// 有任意一个对象元素有此属性且值为黎明时,返回ture,否则返回false
let some = emp.some((item,index) => {
  return item.empName == "黎明"
})
console.log(some); // => true// 有任意一个对象元素有此属性且值为黎明时,返回ture,否则返回false
let someMoney = emp.some((item,index) => {
  return item.money >10000
})
console.log(someMoney); // => true
reduce()与reduceRight()

reduce()和reduceRight()方法使用我们指定的函数归并数组元素,最终产生一个值。在函数编程中,归并是一个常见操作,有时候也称为注入(inject)或折叠(fold)。

什么时候用它?当多个数据最终变成一个数据的时候

reduce()接收两个参数。第一个参数是执行归并操作的函数callback。这个归并函数的任务就是把两个值归并或组合为一个值并返回这个值。第二个参数是可选的,是传给归并函数的初始值。

  • 回调函数callback (执行数组中每个值的函数,包含四个参数): previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue)) currentValue (数组中当前被处理的元素) index (当前元素在数组中的索引) array (调用 reduce 的数组)
  • initialValue (可选,作为第一次调用 callback 的第一个参数,如果为空的话,默认是1,则从数组的第2个元素开始)
// 获取所有雇员的工资合计
let totalMoney = emp.reduce((previousValue, currentValue) => {
  return previousValue + currentValue.money
},0)
console.log(totalMoney);
// 获取所有雇员的工资平均数
let avgMoney = emp.reduce((previousValue, currentValue) => {
  return (previousValue + currentValue.money) / emp.length
}, 0)
console.log(avgMoney);
​
// 获取所有雇员的最高的工资数
let maxMoney = emp.reduce((previousValue, currentValue) => {
  return previousValue > currentValue.money ? previousValue : currentValue.money
}, 0)
console.log(maxMoney);

使用concat()添加数组

concat()方法

concat()方法创建并返回一个新数组,新数组包含调用concat()方法的数组的元素,以及传给concat()的参数。如果这些参数中有数组,则拼接的是它们的元素而非数组本身。但要注意,concat()不会递归打平数组的数组。concat()并不修改调用它的数组。

注意,concat()会创建调用它的数组的副本。很多情况下,这样做都是正确的,只不过操作代价有点大。如果你发现自己正在写类似a = a.concat(x)这样的代码,那应该考虑使用push()或splice()就地修改数组,就不要再创建新数组了。

// 添加一个新元素
let newEmp = emp.concat({
    empId: 5,
    empName: "周杰伦",
    sex: 0,
    age: 31,
    money: 3000
  })
  console.log(newEmp); // =>(5) [{…}, {…}, {…}, {…}, {…}]

栈和队列方法 通过push()、pop()、shift()和unshift()实现栈和队列操作

push()和pop()方法

push()和pop()方法可以把数组作为栈来操作。其中,push()方法用于在数组末尾添加一个或多个新元素,并返回数组的新长度。与concat()不同,push()不会打平数组参数。pop()方法恰好相反,它用于删除数组最后面的元素,减少数组长度,并返回删除的值。注意,这两个方法都会就地修改数组。组合使用push()和pop()可以使用JavaScript数组实现先进后出的栈。

// 在数组后面添加一个周杰伦的数组对象
emp.push({
  empId: 5,
  empName: "周杰伦",
  sex: 0,
  age: 31,
  money: 3000
})
console.log(emp); // =>(5) [{…}, {…}, {…}, {…}, {…}]
// 删除最后一个数组对象
emp.pop()
console.log(emp); // =>(4) [{…}, {…}, {…}, {…}]
// 在数组前面添加一个周杰伦的数组对象 
emp.unshift({
  empId: 5,
  empName: "周杰伦",
  sex: 0,
  age: 31,
  money: 3000
})
console.log(emp); // =>(5) [{…}, {…}, {…}, {…}, {…}]
// 删除最前一个数组对象
emp.shift()
console.log(emp);

子数组方法 使用slice()、splice()、fill()和copyWithin()

数组定义了几个处理连续区域(或子数组,或数组“切片”)的方法。

slice()

slice()方法返回一个数组的切片(slice)或者子数组。这个方法接收两个参数,分别用于指定要返回切片的起止位置。返回的数组包含第一个参数指定的元素,以及所有后续元素,直到(但不包含)第二个参数指定的元素。如果只指定一个参数,返回的数组将包含从该起点开始直到数组末尾的所有元素。如果任何一个参数是负值,则这个值相对于数组长度指定数组元素。比如,参数-1指定数组的最后一个元素,参数-2指定倒数第二个元素。注意,slice()不会修改调用它的数组。

// 截取从下标为0到2的两个元素,即下标是0和1 的数组对象
let newEmp = emp.slice(0,2)
console.log(newEmp);// =>(2) "刘德华" "张学友"// 截取从下标为1到2的两个元素,即下标是1的数组对象
let newEmp1 = emp.slice(1,2)
console.log(newEmp1);// =>(2) "张学友"// 截取从下标为2到最后的元素
let newEmp2 = emp.slice(2)
console.log(newEmp2);// =>(2) "郭富城" "黎明"
// 获取下标从1到3的元素 
// 3 = emp.length -1
let newEmp3 = emp.slice(1,-1)
console.log(newEmp3);// =>(2) "张学友""郭富城" 
// 获取下标从2到3的元素  
//2 = emp.length - 2
//3 =  emp.length - 1
let newEmp4 = emp.slice(-2,-1)
console.log(newEmp4);// =>(1) "郭富城"
splice()

splice()是一个对数组进行插入和删除的通用方法。与slice()和concat()不同,splice()会修改调用它的数组。注意,splice()和slice()的名字非常相似,但执行的操作截然不同。

splice()可以从数组中删除元素,可以向数组中插入新元素,也可以同时执行这两种操作。位于插入点或删除点之后的元素的索引会按照需要增大或减少,从而与数组剩余部分保持连续。splice()的第一个参数指定插入或删除操作的起点位置。第二个参数指定要从数组中删除(切割出来)的元素个数(注意,这里是两个方法的另一个不同之处。slice()的第二个参数是终点。而splice()的第二个参数是长度)。如果省略第二个参数,从起点元素开始的所有数组元素都将被删除。splice()返回被删除元素的数组,如果没有删除元素返回空数组。

// 删除从下标为0到2的两个元素,即下标是0和1 的数组对象
emp.splice(0,2)
console.log(emp); // => "郭富城""黎明"// 删除从下标为2到最后的元素
emp.splice(2)
console.log(emp); // => "刘德华""张学友"

splice()的前两个参数指定要删除哪些元素。这两个参数后面还可以跟任意多个参数,表示要在第一个参数指定的位置插入到数组中的元素。

// 在第一个参数下标为0的位置上插入新的obj对象
let obj = {
  empId: 5,
  empName: "周杰伦",
  sex: 0,
  age: 31,
  money: 3000
}
emp.splice(0,2,obj)
console.log(emp); // => "周杰伦""郭富城""黎明"
fill()

fill()方法将数组的元素或切片设置为指定的值。它会修改调用它的数组,也返回修改后的数组。

let arr = new Array(10)
// 以0填充数组长度为10的arr
arr.fill(0)
console.log(arr); // =>(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 以8填充,从下标为1处开始
arr.fill(8,1)
console.log(arr); // =>(10) [0, 8, 8, 8, 8, 8, 8, 8, 8, 8]
// 以1填充,从下标3-5,即 3和4 被改变
arr.fill(1,3,5)
console.log(arr); // =>(10) [0, 8, 8, 1, 1, 8, 8, 8, 8, 8]
// 以9填充,从下标7到8,即7被改变
arr.fill(9,-3,-2) 
console.log(arr); // =>(10) [0, 8, 8, 1, 1, 8, 8, 8, 8, 8]
copyWithin()

copyWithin()把数组切片复制到数组中的新位置。它会就地修改数组并返回修改后的数组,但不会改变数组的长度。第一个参数指定要把第一个元素复制到的目的索引。第二个参数指定要复制的第一个元素的索引。如果省略第二个参数,则默认值为0。第三个参数指定要复制的元素切片的终止索引。如果省略,则使用数组的长度。从起始索引到(但不包含)终止索引的元素会被复制。与使用slice()一样,也可以传入负值相对于数组末尾指定索引。

// 一个参数,第二个参数无,默认是复制下标为0的元素 刘德华,替换3的元素 黎明
emp.copyWithin(3)
console.log(emp);// =>"刘德华" "张学友" "郭富城" "刘德华"
​
// 两个参数,是复制下标为1的元素 张学友,替换3的元素 黎明
emp.copyWithin(3,1) // =>"刘德华" "张学友" "郭富城" "张学友"
console.log(emp);
​
// 三个参数,第三个参数是到什么位置为止,即下面例子中,不会复制成功
emp.copyWithin(3,1,1)
console.log(emp);
​

数组索引与排序方法

数组实现与字符串的同名方法类似的indexOf()、lastIndexOf()和includes()方法。此外还有sort()和reverse()方法用于对数组元素重新排序。

indexOf()和lastIndexOf()

indexOf()和lastIndexOf()从数组中搜索指定的值并返回第一个找到的元素的索引,如果没找到则返回-1。indexOf()从前到后(或从头到尾)搜索数组,而lastIndexOf()从后向前搜索数组。

indexOf()和lastIndexOf()使用===操作符比较它们的参数和数组元素。如果数组包含对象而非原始值,这些方法检查两个引用是否引用同一个对象。如果想查找对象的内容,可以使用find()方法并传入自定义的断言函数。

indexOf()和lastIndexOf()都接收第二个可选的参数,指定从哪个位置开始搜索。如果省略这个参数,indexOf()会从头开始搜索,lastIndexOf()会从尾开始搜索。第二个参数可以是负值,相对于数组末尾偏移,与slice()方法一样。比如,-1指定数组的最后一个元素。

// 注意查找对象,用以下方式会查不到,得到的是-1,应采用find方法
let obj = {
  empId: 4,
  empName: "黎明",
  sex: 0,
  age: 31,
  money: 3000
}
​
console.log(emp.indexOf(obj));
​
// indexOf 查到返回索引值,下标。查不到返回-1
let arr = [1,2,3,4,5]
console.log(arr.indexOf(1)); // =>0 数字1的下标
console.log(arr.indexOf(8)); // =>-1 找不到返回 -1// lastIndexOf 从后往前查找 例子中两个1
let arr1 = [1,2,3,4,5,1]
console.log(arr1.lastIndexOf(1)); // =>5 从后面找到数字1的下标
includes()

ES2016的includes()方法接收一个参数,如果数组包含该值则返回true,否则返回false。它并不告诉你值的索引,只告诉你是否存在。includes()方法实际上是测试数组的成员是否属于某个集合。不过要注意,数组并非集合的有效表示方式,如果元素数量庞大,应该选择真正的Set对象。

includes()方法与indexOf()方法有一个重要区别。indexOf()使用与===操作符同样的算法测试相等性,而该相等算法将非数值的值看成与其他值都不一样,包括与其自身也不一样。includes()使用稍微不同的相等测试,认为NaN与自身相等。这意味着indexOf()无法检测数组中的NaN值,但includes()可以。

// includes 查找数字1 有的话返回true
let arr1 = [1,2,3,4,5,1]
console.log(arr1.includes(1)); // true// indexOf找不到NaN,includes可以
let arr = [1,true,NaN]
console.log(arr.indexOf(NaN)); // => -1 indexOf 找不到NaN
console.log(arr.includes(NaN));// => true includes 可以找到NaN
sort()

sort()对数组元素就地排序并返回排序后的数组。在不传参调用时,sort()按字母顺序对数组元素排序(如有必要,临时把它们转换为字符串再比较)。

// sort 第一个参数,回调函数为比较函数,传入两个a,b元素进行比较
// 按收入money 升序排列
emp.sort((a, b) => {
  return a.money - b.money
})
console.log(emp);
​
// 按年龄 降序排列
emp.sort((a, b) => {
  return b.age - a.age
})
console.log(emp);
​
// 以汉字的首字母进行升序的,但有多音字无法解决
emp.sort((a, b) =>{
    return a.empName.localeCompare(b.empName, 'zh') //a~z 排序
})
console.log(emp);
reverse()

reverse()方法反转数组元素的顺序,并返回反序后的数组。这个反序是就地反序,换句话说,不会用重新排序后的元素创建新数组,而是直接对已经存在的数组重新排序。

// 反转顺序
emp.reverse()
console.log(emp);

数组到字符串的转换方法

Array类定义了3个把数组转换为字符串的方法,join(),toString(),toLocaleString()

join()方法

join()方法把数组的所有元素转换为字符串,然后把它们拼接起来并返回结果字符串。可以指定一个可选的字符串参数,用于分隔结果字符串中的元素。如果不指定分隔符,则默认使用逗号。

toString()方法

数组也有toString()方法。对于数组而言,这个方法的逻辑与没有参数的join()方法一样。

toLocaleString()方法

toLocaleString()是toString()的本地化版本。它调用toLocaleString()方法将每个数组元素转换为字符串,然后再使用(实现定义的)当地分隔符字符串来拼接结果字符串。在数组使用上,与toString()并无太大区别。

// 按逗号分割,按-分割
let arr = [1,3,5,7,9]  
console.log(arr.join()); // => 1,3,5,7,9
console.log(arr.join('-')); // => 1-3-5-7-9
// toString方法和 join()无参方法一致
console.log(arr.toString()); // => 1,3,5,7,9
console.log(arr.toLocaleString()); // => 1,3,5,7,9
转载自:https://juejin.cn/post/7101639694290534431
评论
请登录