深入数组之梳理数组api

400 阅读8分钟

> 这是我参与新手入门的第2篇文章

前言

javascript数组相信大家都不陌生。在平时学习中,开发项目中大家都会频繁使用数组api,可以说数组在整个javascript的学习过程中尤为重要。我们如果不深入地了解数组,那么很难应付平时的各种需求... 本文将初步带你整理数组眼花缭乱的api,先对数组api有个清晰的认识。同时,在后面几个部分将一起手撕数组扁平化和数组去重,加深对数组api的理解。

怎么判断目标是不是数组呢?

  • 思路1:在es6中新增了一个Array.isArray(arg)方法,能直接判断arg是不是数组。
  • 思路2:直接判断arg是啥类型,之后看是不是数组。那么,怎么判断目标是啥类型呢?Object.prototype.toString.call(arg)能完美判断arg是哪个类型,如果Object.prototype.toString.call(arg) === '[object Array]'那么arg就是数组。
  • 思路3:借助原型链判断。这个思路就有很多种方式了,下面给出总结:
    1Array.isArray(arg) // 思路1
    2Object.prototype.toString.call(arg) === '[object Array]' // 思路2
    //=====以下是思路3======
    3、 arg.constructor === Array //这个判断不一定可靠,因为constructor是可以修改的.
    4Array.prototype.isPrototypeOf(arg) //注意,必须是Array.prototyoe,不能是Array.原因就不用我说了吧
    5Object.getPrototypeOf(arg) === Array.prototype
    6、 arg instanceof Array

数组有哪些改变自身的方法呢?

这里整理了9个会改变自身的方法:

  1. pop() 删除数组最后一个元素,并返回这个元素(空数组为undefined)。
  2. push(*arg1, ..., argN*) 添加元素到数组最后一项,并返回添加元素后的数组长度。
  3. shift() 删除数组第一项,并更新length。返回删除的第一项的值(空数组为undefined).
  4. unshift(*arg1, ..., argN*) 添加元素到数组开头,并返回添加元素后的数组长度(插入顺序与参数顺序一样)。
  5. reverse() 颠倒数组中元素的位置,并返回该数组的引用。
  6. sort([*compareFunction(elem1, elem2)*]) 应用compareFunction进行排序。若没有提供compareFunction,则按照转换为字符的unicode位点进行排序。 具体查看MDN
  7. splice(*start[, deleteCount, arg1, arg2]*) 删除数组从start开始之后的deleteCount个元素,然后将arg1,arg2添加进start之后的位置。返回删除元素组成的数组。注意:start可以是负数,若是负数会变成length + start
  8. fill(*value[, start, end]*)value值替换数组从start下标开始的到end结束的内容。若不提供可选参数,则是替换数组全部内容。返回替换后数组的引用。注意: start可以是负数,若是负数会变成length + start
  9. copyWithin(*target[, start[, end]]*) 将数组下标从start开始到end结束的内容浅复制下标为target位置。注:这是一个高性能的移动数据的方法若参数是负数则会变成length + 其值

数组有哪些不改变自身的方法?

这里整理了几种不改变自身的方法:

  1. concat(*arg1, ..., argN*) 用于合并多个数组。返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本。也就是说,如果引用的对象被修改,则更改对于新数组和原始数组都是可见的。 这包括也是数组的数组参数的元素。 还有就是,concat的参数如果既包含数组,也包含普通类型。对于数组来说,也会将其解构再连接,而不是连接整个数组项。
  2. slice([begin[, end]]) 返回一个由原数组beginend浅拷贝。同时注意slice()是不改变自身的,而splice()却是改变自身的。
  3. includes(*valueToFind[, fromIndex]*) 从数组的fromIndex项开始到结尾,判断是否包含valueToFind,返回一个Boolean。需要注意的是,includes可以检查数组中是否有NaN。对于-0+0是当一回事。相等规则见 MDN:零值相等

image.png image.png

4. indexOf(searchElem[, fromIndex]) 5. lastIndexOf(searchElem[, fromIndex]) 返回在数组中从fromIndex到结尾找到的第一个searchElem 的索引。若不存在则返回-1。注意:indexOf/lastIndexOf都是使用===来判断searchElem与数组项是否相等的. 6. join(seperator) 返回使用seperator将数组的每一项连接成的一个字符串。注意:对于数组项来说,如果值为null或者undefined,再返回结果中则会用空字符串替换

不改变自身的遍历方法

  1. forEach(callBack:(value[, index[, array]])[, thisArg]) 返回undefined,意味着没办法链式调用。 注意的点有:
    (1)、forEach是不改变数组的,但那个数组可能会被callBack改变。
    (2)、遇到空项(稀疏数组)会直接跳过。空项并不是指值为nullundefined的,而是指从未被赋值的
    (3)、除了抛出异常以外,没有办法中止或跳出循环。
    (4)、forEach遍历的元素范围在第一次调用callBack时就确定了。也就是说在迭代时往数组尾部增加元素是没用的;而若是往数组开头加元素的话,会将各元素index + 1,此时可能会出现重复操作某个元素的情况。删除元素的话,若是删除未迭代的元素则跳过该元素; 若是删除已迭代的元素,那么未迭代的元素将依次index - 1,此时或许会出现跳过元素的情况。
  2. every(callBack:(value[, index[, array]])[, thisArg]) 返回一个Boolen。需要注意的是:
    (1)、若是空数组调用这个方法,那么总是返回true。也就是说,若是需要使用every来判断某个数组项时,需要事先排除数组为空的情况。
    (2)、every遍历的元素范围在第一次调用callBack时就确定了。
    (3)、遇到空项(稀疏数组)会直接跳过。空项并不是指值为nullundefined的,而是指从未被赋值的
    (4)、callBack需要返回一个truthy(可以转换为true)值或falsy(可以转换为false)值。every遍历在第一次遇到callBack返回falsy值时中止并退出循环且返回false
  3. some(callBack:(value[, index[, array]])[, thisArg]) 测试数组中是不是至少有1个元素通过了被提供的函数测试。返回一个Boolean。需要注意的有:
    (1)、若是空数组调用这个方法。则总是返回false。
    (2)、遇到空项(稀疏数组)会直接跳过。空项并不是指值为nullundefined的,而是指从未被赋值的
    (3)、some遍历的元素范围在第一次调用callBack时就确定了。
  4. filter(callBack:(value[, index[, array]])[, thisArg]) 其返回一个新数组,其包含原数组所有通过callBack测试的数组项。需要注意的有:
    (1)、遇到空项(稀疏数组)会直接跳过。空项并不是指值为nullundefined的,而是指从未被赋值的
    (2)、filter遍历的元素范围在第一次调用callBack时就确定了。
  5. map(callBack:(value[, index[, array]])[, thisArg]) 返回一个新数组,新数组的每一项都是原数组经过callBack变换而来的。需要注意的有:
    (1)、遇到空项(稀疏数组)会直接跳过。空项并不是指值为nullundefined的,而是指从未被赋值的
    (2)、map遍历的元素范围在第一次调用callBack时就确定了。
    (3)、原数组的空项也会保留在新数组当中。
  6. reduce(callBack:(accumulator[, value[, index[, array]]])[, initialValue]) 返回函数累计器处理的结果。需要注意的是:
    (1)、若调用reduce的数组是空数组且没有提供initialValue.则会抛出TypeError.
    (2)、如果没有提供initialValue,那么accumulator会取数组第一项的值,且从第二项(索引为1)开始调用callBack。所以如果数组只有一项,且没有initialValue,则不会执行callBack. 7. reduceRight() 与reduce相比,取最后一项
  7. find()
  8. findIndex() 这两个与前面的不同:
    (1)、其不会跳过空项.
    (2)、被删除的元素依旧能访问到,但其值为undefined

总结:

本文章介绍了:
判断目标是不是数组的6中方式。(还记得是哪6种不?-。-)
数组改变自身的9个方法:
push,pop,shift,unshift, reverse,sort,splice, fill, copyWithin.
其中:

  • 可以删除元素的方法都返回删除元素(的集合),而splice不管删除多少个都是返回数组,若是指提供start参数不提供deleteCount参数,则返回原数组。
  • 增加元素的方法都是返回增加元素的数组的长度
  • 不增加也不删除的方法返回操作后原数组的引用 数组不改变自身的6个非遍历方法:
    concat, slice, includes, indexOf, lastIndexOf, join
    数组不改变自身的9个遍历方法:
    forEach, every, some, filter, map, reduce, reduceRight, find, findIndex
    其中:
  • 除了reduce/reduceRight外,其他的遍历方法都有一个可选thisArg参数。在传递thisArg参数时需要注意:
    1. callBack不能是箭头函数,不然不然thisArg是什么,都会指向全局对象(window)
    2. 若是传递的thisArg为null或者undefined,则会用window替换thisArg
  • forEach, every, some,filter,map都会:
    1. 跳过空项元素.
    2. 遍历范围都在第一次调用callBack时就确定 还有就是,本文章介绍的所有数组方法都是通用型的。也就是说可以通过方法借用使得类数组对象也能使用这些方法...
      对于方法涉及下标的,若是下标为负数,则会用length + index替换.

觉得不错就点个赞吧~