数组操作一箩筐

190 阅读3分钟

创建数组

// 除了对象字面量直接创建外,我们可以使用Array.from
// 第一个参数是类数组,第二个参数为遍历函数(遍历操作每个元素)
const aa = Array.from(new Array(10), (item,index) => index)
const aa = Array.from({length: 10}, (item, index) => index)

// 下面方式也是可以的-_-
const bb = new Array(10).fill().map((item, index) => index)

数组遍历

forEach、map、filter、every、some、reduce、for of 注意事项

map 返回新数组 forEach、map,不能跳出循环(当然骚操作try、catch可以实现) every (return false 可以跳出循环,使用时注意return true必须写,不可省略) some (return true 可以跳出循环)

forEach方法

数组的forEach方法,用于遍历数组元素,并将数组元素传递给回调函数。使用forEach方法,回调函数有三个参数。

    arr.forEach((item, index, _arr)=>{}, this)
  • this: 回调函数作用域
  • item: 当前项
  • index: 循环索引,下标index
  • _arr: 当前数组

第三个参数是数组本身,它的作用是什么呢?暂时没找到其特殊的用处,权当做参数使用吧。即在回调函数中不需要向上查找数组本身,而可以在方法块里直接拿到使用。

forEach会不会修改原数组

    const arr = [1,2,3,4,5];
    arr.forEach((item, index, _arr) => {
       item *= 2; 
    })
    console.log(arr);
    // (5)[1, 2, 3, 4, 5]
    
    const objArr = [{key: 1}, {key: 2}, {key: 3}]
    objArr.forEach((item) => {
        item.key *= 2;
    })
    console.log(objArr);
    // 0: {key: 2} 
    // 1: {key: 4}
    // 2: {key: 6}
    

这里原数组有没有被修改,其实和forEach没有关系,而是数据类型的影响:基本数据类型(值引用),对象(地址引用)

  • 基本数据类型: Number、String、Boolean、Symbol、Null和undefined
  • 对象(Object)类型: Object

基本数据类型数据存放在栈内存中,变量名和值都在栈内存中;引用数据类型实际数据存放在堆内存中,变量名和地址存放在栈内存中。

forEach是否可以循环删除

在实际开发过程中,我们经常需要遍历数组,剔除数组中的某些元素的需求。forEach遍历数组时,是否可以正确的删除元素呢?

const arr = [1,2,3,4,5];
arr.forEach((item,index)=>{
    if (item>3) {
        arr.splice(index, 1)
    }
})
console.log(arr);
// (4)[1, 2, 3, 5]

上面实例里只删除了4,并没有正确的把4和5删除。原因在于forEach里有隐含逻辑,每次执行有标记index,执行完一次循环后index++,下次循环先拿index和数组长度比较。 所以forEach不能实现循环删除。可以改用普通for循环或者其它方法代替(如filter)

for in 与 for of

for in 一般用来遍历对象。

const obj = {a: 1, b:2, c:3}
for (let key in obj) {
    console.log(key)
}

for循环可以跳出循环(break),而forEach、map不可以。 for in 遍历数组存在的问题:

  • for in会遍历数组的所有可枚举属性,包括其原型的可枚举属性
  • for in 用来遍历数组时,key为索引值,且该索引值是字符串型。 遍历数组,ES6提供了for of方法,可以获取数组每一项。
const arr = [2, 3, 4]
for (let item of arr) {
    console.log(item)
}

数组去重(方法性能比较)

数组去重是面试中经常碰到的问题。去重有多种实现方法,大体可以分为两大类,我们看一下常用方法的性能比较。

  • 利用不可重复语法特点去重
  • 利用双重循环(基于循环遍历比较)

利用语法特性去重

1、indexOf(基于重复元素index是默认第一个重复元素的index)
2、Set (基于集合Set里无重复元素)
3、Object (基于对象Object的key不重复)

// indexOf
const targetArr = originArr.filter((item, index) => originArr.indexOf(item) == index)

// Set
const targetArr = Array.from(new Set(originArr))

indexOf平均耗时约120ms

set去重平均耗时3ms