- 数组对象:是一种特殊的对象
- JS 其实没有真正的数组,只是用对象模拟数组
JS 的数组与典型数组的区别
典型数组
元素的数据类型相同 | ![]() |
---|---|
使用连续的内存存储 | |
通过数字下标获取元素 |
JS 数组
元素的数据类型可以不同 | ![]() |
---|---|
内存不一定是连续的(对象是随机存储的) | |
不能通过数字下标,而是通过字符串下标 | |
这意味着数组可以有任意 key 比如let arr = [1,2,3] arr['xxx'] = 1 |
创建数组
新建
/* 简写形式 */
let arr = [1,2,3] //小白用的居多
/* 规范写法 */
let arr = new Array(1,2,3) //帮助理解
let arr = new Array(3)
// '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变成数组
- `**Array.from**` **需要符合两个条件,才能会将其变成真正的数组?**
- 这个对象有0,1,2,3 这样的下标
- 有 length 属性
<br />
<a name="OdF6S"></a>
#### 伪数组
- 伪数组的原型链中并没有数组的原型,因为它的原型直接指到了对象的原型Object
- 没有数组共用属性的 「数组」就是**伪数组**
- 比如没有 `push、pop` 这些数组的共有属性,那就是伪数组
```javascript
/* 将伪数组转化为数组的示例 */
let divList = document.querySelectorAll('div') //伪数组
let divArray = Array.from(divList) //将伪数组转化为数组
console.dir(divArray)
上面代码打印出来的截图 | |
---|---|
![]() |
![]() |
合并两个数组,得到新数组(变长)
arr1.concat(arr2) |
concat 把一个(或多个)数组和(或)值与原数组拼接, 返回拼接后的数组 |
![]() |
---|---|---|
截取一个数组的一部分(变短)
arr.slice
从原数组里截取部分数组,并且不改变原来的数组
【注意】JS 只提供浅拷贝arr1.slice(1) // 从第二个元素开始截取
/* 全部截取 */
arr1.slice(0) // 常用于复制一个数组
增删改查
**reduce**
和**splice**
是数组里最复杂的,也是功能最强大的,学会了基本上想对数组进行任何操作都是可以的
删数组中的元素
推荐写法
- splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
| 删除头部的元素 |
**arr.shift()**
| 从数组中删除第一个元素,
并返回该元素的值。
此方法更改数组的长度。 || | —- | —- | —- | —- | | 删除尾部的元素 |
**arr.pop()**
| 从数组中删除最后一个元素,
并返回该元素的值。
此方法更改数组的长度。 || | 删除中间的元素 |
**arr.splice(index,1)**
| 从 index 下标的位置开始,删除 1 个元素 || | |
**arr.splice(index,1),'x'**
| 并在删除的位置添加'x'
|| | |
**arr.splice(index,1,'x','y')**
| 并在删除的位置添加'x','y'
||
不推荐的写法
对象的删法 delete 「 不适合删数组」
let arr = ['a','b','c']
delete arr['0']
arr // --> [empty,'b','c'] // 数组的长度不变
- 稀疏数组:只有长度,但没有对应下标的数组。
- 它没有好处,只有bug
直接改 length 删元素 【不推荐】
【注意】不要随便改 length
改 length 会删属性名 且不报错 |
![]() |
---|---|
查看所有元素
查看所有属性名『不推荐』
- 查看对象的写法在数组这里不靠谱 ```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
<a name="oOuPV"></a>
#### 查看数字(字符串)属性名和值『推荐』
1. **用 **`**for**`** 循环**
```javascript
for(let i = 0; i < arr.length; i++){ // 自己控制让 i 从 0 增长到 length-1
console.log(`${i} :${arr[i]}`)
}
for
循环是访问数组的常见形式,几乎可以解决数组的任何问题- 不要用
for in
它是用来访问对象的,也不要用Object.keys
可能会获取到不想要的东西 **${}**
:意思是花括号里可以插入变量
- 用
**forEach**
自己写 forEach 才能理解 forEacharr.forEach(function(item, index){ // forEach 的原理是遍历数组,然后每次调用这个函数
console.log('${item}: ${item}')
})
function forEach(array, fn){
for(let i = 0; i < Array.length; i++){
fn(Array[i],i,Array)
}
}
forEach
用for
访问array
的每一项- 对每一项调用
fn(array[i],i,array)
for 循环和 forEach 的区别是什么?
- 大部分情况下二者几乎通用,只有 for 循环里有
break
和continue
的时候不同
forEach
只是一个普通函数, 是不支持break
和continue
操作的,for
循环是关键字,功能更强大一些- 用
for
循环的时候可以不停的break
和continue
,而forEach
是要开始就要一直走到尾,没有办法结束 - 作用域不同
for
循环是关键字,它不是函数,所以没有函数作用域,只有块级作用域,但forEach
是函数,所以是函数作用域。
查看单个属性
跟对象一样
let arr = [111,222,333]
arr[0]
注意不要索引越界
arr[arr.length] === undefined
arr[-1] === undefined
举例
for(let i=0;i<=arr.length;i++){
console.log(arr[i].toString())
}
报错:Cannot read properties of undefined 看到这个报错的时候很可能索引越界了
- 任何不存在的下标,去读的时候都会得到
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’ |
代码示例:
修改元素
用 splice
修改
arr.splice |
![]() |
---|---|
反转顺序
自定义顺序
| arr.sort((a,b) => a-b)
判断大小排序 | |
如何反转字符串?
- 先将其变成数组,再反转顺序,然后再合成字符串
高级技巧
数组变换
方法 | 用途 | 示例 | 用 **reduce** 代替 **map** 和 **filter** 的写法 |
---|---|---|---|
map |
n 变 n 创建一个新数组, 其结果是该数组中的每个元素 是调用一次提供的函数后的返回值 |
![]() |
![]() |
filter |
n 变少 使用 filter() 根据搜索条件来过滤数组内容 |
![]() |
![]() |
**reduce** |
n 变 1 对数组中的每个元素执行一个 由您提供的reducer函数(升序执行), 将其结果汇总为单个返回 |
![]() arr.reduce 可简化 for 循环的写法![]() 默认初始值为 0,每一次 return 的值作为下一次的结果 |
null |
代码简化:
/* 取偶数 */
arr.filter(item => item %2 ===0 ? true : false)
/* 简写 */
arr.filter(item => item %2 === 0)
sum = sum + arr[i] 可简写为 --> sum += arr[i]
拓展题 | 截图 |
---|---|
![]() |
![]() ![]() |