JavaScript - 数组

225 阅读7分钟

JS数组简介

在JS中,数组是一种特殊的对象,并非是典型的数组,可以理解为用对象模拟数组。

典型的数组

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

image.png

JS的数组

  1. 内存不一定是连续的,在JS中对象是随机存储的
  2. 元素的数据类型可以不同
  3. 不能通过数字下标访问,而是通过字符串下标,也就是说数组可以用任何Key

image.png

例如: 在浏览器控制台声明一个数组let array = [1,2,3]通过Object.keys()可以看到key都是字符串,不是数字。给数组添加一个元素 'xxx' ,可以看到下标是xxx,其实也是字符串。

image.png

创建数组

创建新数组

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(',')

例如:

image.png

除此之外,

  • Array.from 可以把不是数组的东西尝试变成数组
    • 需要满足两个条件
      • 有0/1/2/3/...下标;
      • 有length

如下图:Array.from将字符串和伪数组变成了数组

image.png

但是不满足两个条件的就没有转化成数组 image.png

注意:如果0/1/2/3和length不一致,array.from会根据length的值进行裁剪,会删除后面的。

image.png

合并两个数组

合并得到新的数组,但是并不会影响原来的数组.(JS只提供浅拷贝)

arr1.concat(arr2)

例如:

image.png

截取部分数组

截取得到新的数组,但是并不会影响原来的数组。(JS只提供浅拷贝)

arr1.slice()
例如:
arr1.slice(0)  // 全部截取
arr1.slice(1)  // 从第二个元素截取
// 注意下标是从0开始

例如:

image.png

伪数组

伪数组只是一个普通的对象。拥有 0,1,2,3 和 length ,但不是由Array构造出来(数组都是由 Array 构造出来的)。

  • 伪数组的原型链中没有数组的原型,因为它的原型直接指到了对象Object的原型
  • 伪数组中没有数组所共有的属性,如push、pop等

例如:创建一个数组 array 和一个伪数组 array2

image.png

点开会发现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被修改,并返回被删除的元素

例如:

image.png

删除尾部元素

arr.pop()    // arr被修改,并返回被删除的元素

例如:

image.png

删除中间元素

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'

例如:

image.png

image.png

特别的删除(不推荐)

  • 用delete删除(用和删除对象一样的方法来删除)

image.png

这样删除没有改变 length ,变得只有长度,没有内容,这样的数组成为稀疏数组

  • 改 length

image.png

注意:不要随意更改length,这种方法不推荐

查看元素

查看所有元素

用 Object

Object.keys()  // 查看所有元素属性名

Object.values()  // 查看所有元素属性值

image.png

for 循环

for(let i=0; i<arr.length; i++){
    console.log(`${i}:${arr[i]}`)
}

例如:

image.png

forEach

forEach可以接受一个函数,这个函数可以去遍历数组每一项与元素。

  • forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
  • 注意:forEach() 对于空数组是不会执行回调函数的。
arr.forEach(function(item, index){
  console.log(`${index}: ${item}`)
})

例一:

给 forEach 一个参数,例如给个 i 。那这个 i 就是数组中的每一项元素。 image.png

给 forEach 两个参数,例如给个 x 和 y 。那 y 和 x 就是数组中的下标和每一项元素。 image.png

例二:

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 )) image.png

for循环和forEach的区别

  1. for循环是个关键字,不是函数,没有函数作用域,只有块级作用域; 而 forEach 是函数,括号里是函数作用域
  2. for循环可以随时break或者continue ; forEach 不行,只能从头走到尾

例如:

image.png

查看单个元素

使用下标

arr[下标]

例如:

image.png

  • 注意:索引越界

(如果给的索引不存在就会越界)

例如:

image.png

  • 错误原因:错在<=。因为length这个值是查不到的当i为8时无法tostring。i只能是小于 length。
  • 关于报错:Cannot read properties of undefined
    • 意思是你读取了 undefined 的 toString 属性。undefined 不是对象,没有 toString 属性。在x.toString()中,如果 x 是 undefined 就会有这个报错。 (有这个报错那么可能就是索引越界了。)

用arr.indexOf(item)查找

arr.indexOf(item)可以查看某个元素是否在数组里,在返回索引,不在返回 -1

例如: image.png

使用条件查找元素

  • 用 find 返回第一个满足条件的元素;
  • 用 findIndex 返回第一个满足条件的元素的索引
arr.find(item=>item%2 === 0)  //找到第一个偶数

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

例如: image.png

for循环遍历

image.png

增加元素

在尾部添加元素

arr.push(newitem1)        //修改arr, 返回新长度

arr.push(item1, item2)    //修改arr, 返回新长度

例如: image.png

在头部增加元素

arr.unshift(newitem1)       //修改arr, 返回新长度

arr.unshift(item1, item2)   //修改arr 返回新长度

例如:

image.png

在中间添加元素

arr.splice(3, 0, 'x') // 在第三个位置后面不删除并插入x

arr.splice(2, 1, 'x', 'y') // 在第二个位置后面删除一个并插入x,y

例如:

image.png

修改元素

修改某个元素

用 splice

arr.splice(3, 1, 'x') // 在第三个位置后面删除一个并插入x

image.png

用 arr[index] = intem

image.png

反转顺序

arr.reverse()

arr.reverse()不是生成新的数组,而是把原来的数组变了

例如:

image.png

特例:如何将var s = 'abcd'变成var s = 'dcba'

image.png

(这里报错是因为s是字符串,不能直接 reverse ; 将字符串变成数组,转换后再合成字符串)

自定义排序

arr.sort()
  • arr.sort是JS直接写好的排序(默认从小到大),会改变原来的数组
  • arr.sort可以接受一个函数使数组元素按照想要的顺序排序。
  • arr.sort可以按照想要的方式排序,但是要在函数中说明哪个大哪个小。因此,在函数中要声明两个参数,将其比较,需要返回“1 , 0 ,-1”三个值(1表示前面的大;0表示一样大;-1表示后面的大)

例一:

image.png

例二:

image.png

例三:

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
    }
})

可以得到成绩从大到小排序:

image.png

这里的arr.sort()可以简写成

arr.sort((a, b) => a.score - b.score)

直接用a成绩减去b成绩的正负判断

数组变换

map

  • (n变n)对数组每一项进行一一调用,使得 item 变成 newitem 再返回到数组里面
  • 生成新的数组,不会改变原数组

例一:

image.png

例二:(把数字变成日期)

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变少)筛选数组中的元素
  • 生成新的数组,不会改变原数组

例一:

image.png

( 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 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
  • 生成新的数组,不会改变原数组

例一:(求和)

image.png

  • sum是求和函数
  • 0是初始值

例二:(求平方)

image.png

  • []指初始值是一个空数组

例三:(筛选偶数)

image.png

其中 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 

资料来源:饥人谷