JS数组简介
在JS中,数组是一种特殊的对象,并非是典型的数组,可以理解为用对象模拟数组。
典型的数组
- 使用连续的内存存储
- 元素的数据类型相同
- 通过数字下标获取元素
JS的数组
- 内存不一定是连续的,在JS中对象是随机存储的
- 元素的数据类型可以不同
- 不能通过数字下标访问,而是通过字符串下标,也就是说数组可以用任何Key
例如:
在浏览器控制台声明一个数组let array = [1,2,3]通过Object.keys()可以看到key都是字符串,不是数字。给数组添加一个元素 'xxx' ,可以看到下标是xxx,其实也是字符串。
创建数组
创建新数组
let arr = new Array(1, 2, 3)
let arr = new Array(3)
let arr = [1, 2, 3]
- 可以用两种方式创建,第一种是标准写法,不常用 ;第二种是简写,比较常用。
- 第一种方法创建数组时注意:括号里只有一个数,表示的是数组长度;有多个数则表示的是元素
转化成数组
- split 可以将 字符串 转化成数组
let str = '123'
str.split('')
let arr = '1,2,3'
split(',')
例如:
除此之外,
- Array.from 可以把不是数组的东西尝试变成数组
- 需要满足两个条件
- 有0/1/2/3/...下标;
- 有length
- 需要满足两个条件
如下图:Array.from将字符串和伪数组变成了数组
但是不满足两个条件的就没有转化成数组
注意:如果0/1/2/3和length不一致,array.from会根据length的值进行裁剪,会删除后面的。
合并两个数组
合并得到新的数组,但是并不会影响原来的数组.(JS只提供浅拷贝)
arr1.concat(arr2)
例如:
截取部分数组
截取得到新的数组,但是并不会影响原来的数组。(JS只提供浅拷贝)
arr1.slice()
例如:
arr1.slice(0) // 全部截取
arr1.slice(1) // 从第二个元素截取
// 注意下标是从0开始
例如:
伪数组
伪数组只是一个普通的对象。拥有 0,1,2,3 和 length ,但不是由Array构造出来(数组都是由 Array 构造出来的)。
- 伪数组的原型链中没有数组的原型,因为它的原型直接指到了对象Object的原型
- 伪数组中没有数组所共有的属性,如push、pop等
例如:创建一个数组 array 和一个伪数组 array2
点开会发现array(数组)有两层的Prototype,第一层有push、pop等数组所共有的属性,第二层才指向对象Object的原型;但是array2(伪数组)只有一层Prototype,它的原型直接指到了对象Object的原型。
常见的伪数组
- 使用
let divList = document.querySelectorAll('div')获取所有的div所得到的数组是伪数组
例如:
HTML
<body>
<div>1<div>
<div>2<div>
<div>3<div>
</body>
JavaScript
let divList = document.querySelectorAll('div');
console.dir(divList);
运行后浏览器控制台可看到,没有数组共有属性,是个伪数组。使用divList.push(4)会报错说divList.push不是一个函数。
Array.from可以将伪数组转化成数组,可以做作如下更改:
JavaScript
let divList = document.querySelectorAll('div');
let divArray = Array.from(divList);
console.dir(divList);
数组元素的增删改查
删元素
删除头部元素
arr.shift() // arr被修改,并返回被删除的元素
例如:
删除尾部元素
arr.pop() // arr被修改,并返回被删除的元素
例如:
删除中间元素
arr.splice(index, 1) // 删除从Index位置开始的第一个元素
arr.splice(index, 3) // 删除从Index位置开始的3个元素
arr.splice(index, 2, 'x') // 删除从Index位置开始的2个元素,并添加'x'
arr.splice(index, 2, 'x', 'y') // 删除从Index位置开始的2个元素,并添加'x'和'y'
例如:
特别的删除(不推荐)
- 用delete删除(用和删除对象一样的方法来删除)
这样删除没有改变 length ,变得只有长度,没有内容,这样的数组成为稀疏数组
- 改 length
注意:不要随意更改length,这种方法不推荐
查看元素
查看所有元素
用 Object
Object.keys() // 查看所有元素属性名
Object.values() // 查看所有元素属性值
for 循环
for(let i=0; i<arr.length; i++){
console.log(`${i}:${arr[i]}`)
}
例如:
forEach
forEach可以接受一个函数,这个函数可以去遍历数组每一项与元素。
- forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
- 注意:forEach() 对于空数组是不会执行回调函数的。
arr.forEach(function(item, index){
console.log(`${index}: ${item}`)
})
例一:
给 forEach 一个参数,例如给个 i 。那这个 i 就是数组中的每一项元素。
给 forEach 两个参数,例如给个 x 和 y 。那 y 和 x 就是数组中的下标和每一项元素。
例二:
forEach接受一个数组和一个函数,当运行forEach时它会遍历这个函数(从0到length减一) 获取数组里的每一项,把每一项作为fn的参数传给fn
function forEach(array, fn){
for(let i=0; i<array.length; i++){
fn(array[i], i, array)
}
}
获取三个参数(x,y,z),当前元素、下标以及元素本身
forEach(['a','b','c'], function(x,y,z){console.log(x,y,z) })
结果如下图:(forEach就是用for循环访问array的每一项,对每一项调用fn( arr[i], i, array ))
for循环和forEach的区别
- for循环是个关键字,不是函数,没有函数作用域,只有块级作用域; 而 forEach 是函数,括号里是函数作用域
- for循环可以随时break或者continue ; forEach 不行,只能从头走到尾
例如:
查看单个元素
使用下标
arr[下标]
例如:
- 注意:索引越界
(如果给的索引不存在就会越界)
例如:
- 错误原因:错在
<=。因为length这个值是查不到的当i为8时无法tostring。i只能是小于 length。 - 关于报错:
Cannot read properties of undefined- 意思是你读取了 undefined 的 toString 属性。undefined 不是对象,没有 toString 属性。在
x.toString()中,如果 x 是 undefined 就会有这个报错。 (有这个报错那么可能就是索引越界了。)
- 意思是你读取了 undefined 的 toString 属性。undefined 不是对象,没有 toString 属性。在
用arr.indexOf(item)查找
arr.indexOf(item)可以查看某个元素是否在数组里,在返回索引,不在返回 -1 。
例如:
使用条件查找元素
- 用 find 返回第一个满足条件的元素;
- 用 findIndex 返回第一个满足条件的元素的索引
arr.find(item=>item%2 === 0) //找到第一个偶数
arr.findIndex(item=>item%2 === 0) //找到第一个偶数的索引
例如:
for循环遍历
增加元素
在尾部添加元素
arr.push(newitem1) //修改arr, 返回新长度
arr.push(item1, item2) //修改arr, 返回新长度
例如:
在头部增加元素
arr.unshift(newitem1) //修改arr, 返回新长度
arr.unshift(item1, item2) //修改arr 返回新长度
例如:
在中间添加元素
arr.splice(3, 0, 'x') // 在第三个位置后面不删除并插入x
arr.splice(2, 1, 'x', 'y') // 在第二个位置后面删除一个并插入x,y
例如:
修改元素
修改某个元素
用 splice
arr.splice(3, 1, 'x') // 在第三个位置后面删除一个并插入x
用 arr[index] = intem
反转顺序
arr.reverse()
arr.reverse()不是生成新的数组,而是把原来的数组变了
例如:
特例:如何将var s = 'abcd'变成var s = 'dcba'
(这里报错是因为s是字符串,不能直接 reverse ; 将字符串变成数组,转换后再合成字符串)
自定义排序
arr.sort()
arr.sort是JS直接写好的排序(默认从小到大),会改变原来的数组arr.sort可以接受一个函数使数组元素按照想要的顺序排序。arr.sort可以按照想要的方式排序,但是要在函数中说明哪个大哪个小。因此,在函数中要声明两个参数,将其比较,需要返回“1 , 0 ,-1”三个值(1表示前面的大;0表示一样大;-1表示后面的大)
例一:
例二:
例三:
let arr = [
{name:'小明', score:99},{name:'小红', score:77},{name:'小蓝', score:88},
]
arr.sort(function(a, b){
if (a.score > b.score) {
return -1
} else if (a.score === b.score) {
return 0
} else {
return 1
}
})
可以得到成绩从大到小排序:
这里的arr.sort()可以简写成
arr.sort((a, b) => a.score - b.score)
直接用a成绩减去b成绩的正负判断
数组变换
map
- (n变n)对数组每一项进行一一调用,使得 item 变成 newitem 再返回到数组里面
- 生成新的数组,不会改变原数组
例一:
例二:(把数字变成日期)
let arr = [0,1,2,2,3,3,3,4,4,4,4,6]
let arr2 = arr.map(补全代码)
console.log(arr2)
答案:
let arr = [0,1,2,2,3,3,3,4,4,4,4,6]
let arr2 = arr.map((i)=>{
return {0:'周日',1:'周一',2:'周二',3:'周三',4:'周四',5:'周五',6:'周六'}[i]
})
console.log(arr2)
filter
- (n变少)筛选数组中的元素
- 生成新的数组,不会改变原数组
例一:
( true 和 false 可以省略)
例二:(找出所有大于 60 分的成绩)
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let scores2 = scores.filter(补全代码)
console.log(scores2)
答案:
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let scores2 = scores.filter(n => n>= 60)
console.log(scores2)
( 95,91,82,72,85,67,66, 91)
reduce
- 对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
- 生成新的数组,不会改变原数组
例一:(求和)
sum是求和函数- 0是初始值
例二:(求平方)
[]指初始值是一个空数组
例三:(筛选偶数)
其中 if else 可以简写成
arr.reduce((result, item) => result.concat(item%2===0? item : [] ), [])
例四:(算出所有奇数之和)
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let sum = scores.reduce((sum, n)=>{
补全代码
},0)
console.log(sum)
答案:
let scores = [95,91,59,55,42,82,72,85,67,66,55,91]
let sum = scores.reduce((sum, n)=>{
return n%2===0?sum:sum+n
},0)
console.log(sum) // 奇数之和:598
资料来源:饥人谷