一文全面掌握JS数组

前言

前面更新了5篇可视化的相关文章:
从表情包来学canvas 从英雄联盟来学pixi.js 从表情包来学JS动画
从梦幻西游学会广度优先搜索和A*算法 手把手编写一个VUE简易SVG动画组件面试

实习生跟我说看不懂,但愿我能更新一些简单易懂的, ┭┮﹏┭┮,本期更一波JS数组,从用法到常见考点以及手写数组部分方法,全面掌握数组。算法

数组

数组是指一组数据的集合,其中的每一个数据被称做元素,在数组中能够存听任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。canvas

push

做用:向数组的末尾添加一个或更多元素
参数:(item1, item2, ...)
返回值: push完成后数组的新长度数组

let arr = []
arr.push(1)
arr.push(2,3,4)
console.log(arr) // [1, 2, 3, 4]
复制代码

pop

做用:删除数组的最后一个元素
参数: 无
返回值: 被删除的元素markdown

let arr = [1,2,3,4]
let res = arr.pop()
console.log(res, arr) // 4  [1, 2, 3]
复制代码

shift

做用:删除数组的第一个元素
参数: 无
返回值: 被删除的元素app

let arr = [1,2,3,4]
let res = arr.shift()
console.log(res, arr) // 1 [2,3,4]
复制代码

unshift

做用:从数组的头部添加元素
参数: (item1, item2, ...)
返回值: 数组的长度dom

let arr = [1,2,3,4]
let res = arr.unshift()
console.log(res, arr) // 1 [2,3,4]
复制代码

slice

做用:截取新数组
参数:(start,end)
返回值: 截取部分的新数组函数

let arr = [1,2,3,4]
let res = arr.slice(1)
console.log(res, arr) // [2, 3, 4] [1, 2, 3, 4]
复制代码

splice

做用:截取新数组
参数:(index,howmany,item)post

index howmany item
必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 要删除的项目数量。若是设置为 0,则不会删除项目。 可选。向数组添加的新项目。

返回值: 截取部分的新数组动画

let arr = [1,2,3,4]
arr.splice(2, 1, 'test')
console.log(arr) //  [1, 2, "test", 4]
复制代码

reverse

做用:颠倒数组中元素的顺序
参数: 无
返回值: 颠倒顺序的数组, 这里的方法不直接修改原数组,而不是建立新数组

let arr = [1,2,3,4]
let res = arr.reverse()
console.log(res, arr) // [4, 3, 2, 1]  [4, 3, 2, 1] 
复制代码

join

做用:按照指定的分隔符,将数组分割成字符串
参数: (separator)
返回值: 数组分割后的字符串

let arr = [1,2,3,4]
let res = arr.join('-')
console.log(res, arr) // 1-2-3-4  [1, 2, 3, 4]
复制代码

concat

做用:拼接两个或者多个数组
参数: (arr1, arr2, ...)
返回值: 返回拼接后的数组, 该方法不会影响原数组,而是返回新建立的数组

let arr = [1,2,3,4]
let res1 = arr.indexOf(5)
let res2 = arr.indexOf(1)
console.log(res1, res2)
let arr2 = [5,6,7]
let res = arr.concat(arr2)
console.log(res, arr) // [1, 2, 3, 4, 5, 6, 7]  [1, 2, 3, 4]
复制代码

indexOf

做用:用于查找数组中是否存在某个值
参数: (value) 查找的值
返回值: 若是存在查找的值,返回对应的下标,不然返回-1

let arr = [1,2,3,4]
let res1 = arr.indexOf(5)
let res2 = arr.indexOf(1)
console.log(res1, res2) // -1 0
// 一般咱们用if来判断indexOf不喜欢用 === -1的写法, 在一些老代码中有奇特的写法
if (!~arr.indexOf(5)) {
    console.log('这写法好骚啊')
}
// 这样写新手容易看不明白,虽是奇技淫巧,但可读性不高,建议使用includes方法
复制代码

includes

做用:用于查找数组中是否存在某个值
参数: (value) 查找的值
返回值: 若是存在查找的值,若是存在返回true不然返回false

let arr = [1,2,3,4]
let res1 = arr.includes(5)
let res2 = arr.includes(1)
console.log(res1, res2) // false true

复制代码

find

做用:用于查找数组中是否存在某个值
参数: (fn) 匹配函数
返回值: 若是存在查找的值,若是返回第一个符合条件的元素不然返回undefined

let arr = [1,2,3,4]
let res1 = arr.find(item => item > 1)
let res2 = arr.find(item => item > 100)
console.log(res1, res2) // 2 undefined
复制代码

findIndex

做用:用于查找数组中是否存在某个值
参数: (fn) 匹配函数
返回值: 若是存在查找的值,若是返回第一个符合条件的元素下标不然返回-1

let arr = [1,2,3,4]
let res1 = arr.findIndex(item => item === 1)
let res2 = arr.findIndex(item => item === 100)
console.log(res1, res2) // 0 -1
复制代码

sort

做用:数组排序
参数: (fn) 排序函数
返回值:排序后的数组

V8 引擎 sort 函数使用插入排序和快速排序来实现排序算法,当数组长度小于10采用的是插入排序,否者使用快速排序

let arr = [1,2,3,4]
arr.sort((a,b) => {
    return b - a
})
console.log(arr) // [4,3,2,1]

复制代码

fill

做用:给数组填充输入的值
参数:(value)
返回值: 填充后的数组,仍是指向原数组

let arr = [1,2,3,4]
let res = arr.fill(5)
console.log(arr) // [5,5,5,5]
console.log(res) // [5,5,5,5]
复制代码

map

做用:返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
参数:(fn, index, self)
返回值: 计算后的新数组 不影响原来的数组 map() 不会对空数组进行检测

let arr = [1,2,3,4]
let res = arr.map(item => {
    return item *item
})
console.log(arr, res) // [1, 2, 3, 4]  [1, 4, 9, 16]
// 建立多个模拟数据 不会对空数组进行检测 须要先fill在map
let mockArr = new Array(10).fill(0).map((item, index) => {
    return `test-${index}`
})
复制代码

forEach

做用:遍历数组
参数: (fn, index, self)
返回值: 返回undefined

let arr = [1,2,3,4]
let res = arr.forEach((item, index, self) => {
    console.log(item)
})
console.log(res) // undefined
复制代码

some

做用:检测数组中是否有元素知足条件
参数: (fn) 判断条件函数
返回值: Boolean 知足条件true不然false

let arr = [1, 2, 3, 4];
let res = arr.some(item => item > 0)
console.log(res) // true
复制代码

every

做用:检测数组中是否所有元素知足条件
参数: (fn) 判断条件函数
返回值: Boolean 知足条件true不然false

let arr = [1, 2, 3, 4];
let res1 = arr.every(item =>  item > 0)
let res2 = arr.every(item =>  item > 2)
console.log(res1, res2) // false
复制代码

filter

做用:按条件过滤返回新数组
参数: (fn) 判断条件函数
返回值: 返回符合条件的新数组

let arr = [1, 2, 3, 4];
let res = arr.filter(item => {return item > 2})
console.log(arr, res) // [1, 2, 3, 4]  [3, 4]
复制代码

reduce

做用:接收一个函数做为累加器,数组中的每一个值(从左到右)开始缩减,最终计算为一个值。对空数组是不会执行回调函数的 参数: (fn, initialValue)
fn 为计算函数
fn的参数:

total currentValue currentIndex arr
初始值, 或者计算结束后的返回值 当前元素 前元素的索引 当前元素所属的数组对象

initialValue 是初始值 返回值: 返回计算结果

let arr = [1, 2, 3, 4]
let res = arr.reduce(function(prev, cur, index, arr) {
    return prev + cur;
})
console.log(arr, res); // [1, 2, 3, 4] 10
复制代码

Array.isArray

做用:判断变量是否为数组
参数: 判断的变量
返回值: Boolean 知足条件true不然false

let res1 = Array.isArray([])
let res2 =  Array.isArray({})
console.log(res1, res2) // true false
复制代码

Array.from

做用:从一个相似数组或可迭代对象建立一个新的,浅拷贝的数组实例
参数: (arrayLike, mapFn, thisArg)

arrayLike mapFn thisArg
想要转换成数组的伪数组对象或可迭代对象 可选,若是指定了该参数,新数组中的每一个元素会执行该回调函数 可选参数,执行回调函数 mapFn 时 this 对象

返回值: 新数组

let res = Array.from(document.querySelectorAll("div"))
console.log(res) 
复制代码

Array.of

做用:建立新数组
参数: (item...) 要建立的数据
返回值: 建立的新数组

let arr = Array.of(1, 2, 3,4)
console.log(arr) // [1,2,3,4]
复制代码

数组与纯函数

一个函数的返回结果只依赖于它的参数,而且在执行过程里面没有反作用,这个函数叫作纯函数。
数组中,会改变原数组的方法: splice、reverse、sort、push、pop、shift、unshift、fill。 在数组中,咱们认为纯函数有2个特色

  1. 不改变原数组
  2. 返回一个数组

符合数组纯函数条件的有:map、concat、filter、slice

数组方法ES分类

虽然是没什么太大意义的八股文,仍是分类一下吧
ES5:
push、 pop、 shift、 unshift、 splice、 slice、 cancat、 sort、 join、 reverse、
indexOf、forEach、 map、 filter、 every、 some、 reduce、 toString、 Arrary.isArray

ES6:
includes flat find findindex fill Array.from Array.of

类数组

不是数组,拥有length属性,而且属性key由非负数的下标构成

let arrayLike = {
    length: 4,
    1: 'a',
    2: 'b',
    3: 'c'
}
复制代码

常见的类数组

  1. 函数内部的argument
  2. document.querySelectorAll 返回的dom元素列表

类数组中数组方法调用

利用Array.prototype调用数组的方法

Array.prototype.slice.call(arrayLike, 1)
复制代码

类数组转换数组

  1. 扩展运算符
let arr = [...arrayLike]
复制代码
  1. Array.from
Array.from(arrayLike)
复制代码

如何判断变量是不是数组

  1. Array.isArray
let a = []
console.log(Array.isArray(a)) //true
复制代码
  1. instanceof
let a = []
console.log(a instanceof Array) //true
复制代码
  1. constructor
let a = []
console.log(a.constructor Array) //true
复制代码
  1. Object.toString
let a=[];
console.log(Object.prototype.toString.call(a)==='[object Array]') //true
复制代码

如何中断forEach

其实forEach的设计,就是不可中断的,可是有面试官会问,常见的答案是如下2种。

  1. 捕获异常 try-catch
  2. 使用every代替

两种方法都很差,try-catch写起来相对来讲有破坏代码的感受, 而使用every则违背了题目的意思,并无从本质上解决forEach,只是换了方法。
若是工做上有须要中断遍历的时候,仍是尽可能使用for循环,配合break

let arr = [1,2,3,4,5,6,7]
try{
    arr.forEach(item => {
        if(item ===2) {
            trow new Error('中断')
        }
        console.log(item)
    })
}catch(e) {
    console.log('捕获异常',e)
}


复制代码

手写数组方法

forEach

Array.prototype.myforEach = function(fn) {
    if(typeof fn !== "function"){
        throw "参数必须为函数"
    }
    let arr = this;
    for(let i = 0; i <arr.length; i++){
        fn(arr[i], i ,arr)
    }
}
复制代码

every

Array.prototype.every= function(fn){
    if(typeof fn !== "function"){
        throw "参数必须为函数"
    }
    let arr = this
    for(let i=0;i < arr.length; i++){
        let flag = fn(arr[i], i, arr);
        if( !flag ){
             return false
        }		
    }
    return true
}
复制代码

手写完forEach 和 every 也就能明白为何forEach不能中断而every能够中断了。

flat

数组扁平化在面试中也是算毕竟高频的题目

function flat(arr, num = 1) {
  return num > 0
    ? arr.reduce(
        (pre, cur) =>
          pre.concat(Array.isArray(cur) ? flat(cur, num - 1) : cur),
        []
      )
    : arr.slice();
}
复制代码

最后

数组虽然是基础,也是新手的面试高频考点,仍是要牢固掌握,文本介绍了数组的基本使用和一些常见考点,但愿文章对你有帮助,我是阿隆,咱们下期见。

相关文章
相关标签/搜索