• 数组对象:是一种特殊的对象
  • JS 其实没有真正的数组,只是用对象模拟数组

JS 的数组与典型数组的区别

典型数组

元素的数据类型相同 1.png
使用连续的内存存储
通过数字下标获取元素

JS 数组

元素的数据类型可以不同 2.png
内存不一定是连续的(对象是随机存储的)
不能通过数字下标,而是通过字符串下标
这意味着数组可以有任意 key 比如
let arr = [1,2,3]
arr['xxx'] = 1

创建数组

新建

  1. /* 简写形式 */
  2. let arr = [1,2,3] //小白用的居多
  3. /* 规范写法 */
  4. let arr = new Array(1,2,3) //帮助理解
  5. let arr = new Array(3)
  6. // '3'指的是字符串的长度,而不是指它的第一个元素是3
  • 当参数只有1个,那它就是指长度
  • 若参数有多个,那这里便是指元素,而不是长度

转化

  • 通过字符串来创建数组 ```javascript / 用逗号来分隔字符串 / let arr = ‘1,2,3’.split(‘,’) —>[“1”,”2”,”3”]

/ 用空字符串来分隔字符串 / let arr = ‘1,2,3’.split(‘’) —>[“1”,”2”,”3”]

/ 最新ES提供的写法 / Array.from(1,2,3) // 把不是数组的东西通过Array.from变成数组

  1. - `**Array.from**` **需要符合两个条件,才能会将其变成真正的数组?**
  2. - 这个对象有0123 这样的下标
  3. - length 属性
  4. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22104007/1637292634494-37383ecc-44f2-4d91-ac8e-f2e78659917c.png#clientId=u9704b66e-747b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=132&id=u8537b68c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=264&originWidth=758&originalType=binary&ratio=1&rotation=0&showTitle=false&size=78322&status=done&style=none&taskId=ucb8f8cdf-7d8a-4322-a6e4-9bd1ab6d44a&title=&width=379)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22104007/1637292719473-b20c40c4-7873-4dd9-a6b0-56f15ef16af3.png#clientId=u9704b66e-747b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=49&id=u8b00e538&margin=%5Bobject%20Object%5D&name=image.png&originHeight=97&originWidth=768&originalType=binary&ratio=1&rotation=0&showTitle=false&size=37870&status=done&style=none&taskId=u88a0cec3-dcfa-43c9-89f8-8521a177104&title=&width=384)
  5. <a name="OdF6S"></a>
  6. #### 伪数组
  7. - 伪数组的原型链中并没有数组的原型,因为它的原型直接指到了对象的原型Object
  8. - 没有数组共用属性的 「数组」就是**伪数组**
  9. - 比如没有 `push、pop` 这些数组的共有属性,那就是伪数组
  10. ```javascript
  11. /* 将伪数组转化为数组的示例 */
  12. let divList = document.querySelectorAll('div') //伪数组
  13. let divArray = Array.from(divList) //将伪数组转化为数组
  14. console.dir(divArray)
上面代码打印出来的截图
image.png image.png

合并两个数组,得到新数组(变长)

arr1.concat(arr2) concat 把一个(或多个)数组
和(或)值与原数组拼接,
返回拼接后的数组
image.png

截取一个数组的一部分(变短)

  • arr.slice 从原数组里截取部分数组,并且不改变原来的数组
    1. arr1.slice(1) // 从第二个元素开始截取
    2. /* 全部截取 */
    3. arr1.slice(0) // 常用于复制一个数组
    【注意】JS 只提供浅拷贝

增删改查

**reduce** **splice** 是数组里最复杂的,也是功能最强大的,学会了基本上想对数组进行任何操作都是可以的


删数组中的元素

推荐写法

  • splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 | 删除头部的元素 | **arr.shift()** | 从数组中删除第一个元素,
    并返回该元素的值。
    此方法更改数组的长度。 | image.png | | —- | —- | —- | —- | | 删除尾部的元素 | **arr.pop()** | 从数组中删除最后一个元素,
    并返回该元素的值。
    此方法更改数组的长度。 | image.png | | 删除中间的元素 | **arr.splice(index,1)** | 从 index 下标的位置开始,删除 1 个元素 | image.png | | | **arr.splice(index,1),'x'** | 并在删除的位置添加 'x'
    | image.png | | | **arr.splice(index,1,'x','y')** | 并在删除的位置添加 'x','y' | image.png |

不推荐的写法

对象的删法 delete 「 不适合删数组」

  1. let arr = ['a','b','c']
  2. delete arr['0']
  3. arr // --> [empty,'b','c'] // 数组的长度不变
  • 稀疏数组:只有长度,但没有对应下标的数组。
    • 它没有好处,只有bug

直接改 length 删元素 【不推荐】
【注意】不要随便改 length

改 length 会删属性名
且不报错
image.png

查看所有元素

查看所有属性名『不推荐』

  • 查看对象的写法在数组这里不靠谱 ```javascript let arr = [1,2,3,4,5] arr.x = ‘x’ / 遍历所有属性名的方法 / Object.keys(arr) —> // [‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘x’]

/ 遍历所有属性名的方法 / Object.values(arr) —> // [1, 2, 3, 4, 5, ‘x’]

/ 把 arr 里的所有 i 都访问一遍 / for(let i in arr){ // for in 它是用来访问对象的 console.log(i) } —> // 0 1 2 3 4 x

  1. <a name="oOuPV"></a>
  2. #### 查看数字(字符串)属性名和值『推荐』
  3. 1. **用 **`**for**`** 循环**
  4. ```javascript
  5. for(let i = 0; i < arr.length; i++){ // 自己控制让 i 从 0 增长到 length-1
  6. console.log(`${i} :${arr[i]}`)
  7. }
  • for 循环是访问数组的常见形式,几乎可以解决数组的任何问题
  • 不要用 for in 它是用来访问对象的,也不要用 Object.keys 可能会获取到不想要的东西
  • **${}** :意思是花括号里可以插入变量
  1. **forEach**
    1. arr.forEach(function(item, index){ // forEach 的原理是遍历数组,然后每次调用这个函数
    2. console.log('${item}: ${item}')
    3. })
    自己写 forEach 才能理解 forEach
    1. function forEach(array, fn){
    2. for(let i = 0; i < Array.length; i++){
    3. fn(Array[i],i,Array)
    4. }
    5. }
  • forEachfor 访问 array 的每一项
  • 对每一项调用 fn(array[i],i,array)

for 循环和 forEach 的区别是什么?

  • 大部分情况下二者几乎通用,只有 for 循环里有 breakcontinue 的时候不同
  1. forEach 只是一个普通函数, 是不支持 breakcontinue 操作的,for 循环是关键字,功能更强大一些
  2. for 循环的时候可以不停的 breakcontinue,而forEach 是要开始就要一直走到尾,没有办法结束
  3. 作用域不同
    1. for 循环是关键字,它不是函数,所以没有函数作用域,只有块级作用域,但 forEach函数,所以是函数作用域

查看单个属性

跟对象一样

  1. let arr = [111,222,333]
  2. arr[0]

注意不要索引越界

  1. arr[arr.length] === undefined
  2. arr[-1] === undefined

举例

  1. for(let i=0;i<=arr.length;i++){
  2. console.log(arr[i].toString())
  3. }

报错:Cannot read properties of undefined 看到这个报错的时候很可能索引越界了
image.png

  • 任何不存在的下标,去读的时候都会得到 undefined
  • undefined 不是一个对象,所以它没有 toString

如何解决这个问题?
哪个地方有问题,就用 console.log 将其打印出来即可

查找某个元素是否在数组里

  • arr.indexOf(item) 存在返回索引,否则返回 -1

    使用条件查找元素

  • 根据 find 里的条件找到符合条件为true 的第一个元素

  • arr.find(item => item % 2 === 0) 找第一个偶数

    使用条件查找元素的索引

  • arr.findIndex:返回对应元素的索引

  • arr.findIndex(item => item % 2 === 0) 找第一个偶数的索引

增元素

|

在尾部加元素

arr.push(element1, ..., elementN) **push()** 方法将一个或多个元素添加到数组的末尾
并返回该数组的新长度

在头部加元素

| arr.unshift(element1, ..., elementN) | **unshift()** 方法将一个或多个元素添加到数组的开头
并返回该数组的新长度(该方法修改原有数组)。 | |

在中间加元素

| arr.**splice**(index,0,'x') | 0 的意思是一个也不删,在 index 的位置加上 ‘x’ |

代码示例:
image.png

修改元素

|

splice 修改

arr.splice image.png

反转顺序

| arr.reverse():修改原数组 | image.png | |

自定义顺序

| arr.sort((a,b) => a-b)
判断大小排序 | image.pngimage.png |

如何反转字符串?

  • 先将其变成数组,再反转顺序,然后再合成字符串
  • image.png

高级技巧

数组变换

方法 用途 示例 **reduce** 代替 **map****filter** 的写法
map n 变 n

创建一个新数组,
其结果是该数组中的每个元素
是调用一次提供的函数后的返回值
image.png image.png
filter n 变少

使用 filter() 根据搜索条件
来过滤数组内容
image.png image.png
**reduce** n 变 1

对数组中的每个元素执行一个
由您提供的reducer函数(升序执行),
将其结果汇总为单个返回
image.png
arr.reduce 可简化 for 循环的写法
image.png
默认初始值为 0,每一次 return 的值作为下一次的结果
null

代码简化:

  1. /* 取偶数 */
  2. arr.filter(item => item %2 ===0 ? true : false)
  3. /* 简写 */
  4. arr.filter(item => item %2 === 0)
  1. sum = sum + arr[i] 可简写为 --> sum += arr[i]
拓展题 截图
image.png image.png
image.png