概述
- 数组是属于线性结构的一种。
- 就像停车场的停车位一样,是顺序存储数据的结构。
- 解析一下,数组就是一个有序的元素序列,用于存储多个相同类型数据的集合。
- 但在JavaScript这个语言中,一个数组里的元素并不强调是同一类型,可以包含多个数据类型的元素。
属性
- 数组里的各个变量称为数组的元素。
- 用于区分各个元素的数组编号称为下标。
- 容纳元素的总数为数组的长度。
常见的数组操作方法
- 增加
方法一: unshift 前增
let arr = [1];
arr.unshift(2); // [2,1]
作用:向数组头部添加元素。
返回值:返回添加后的新数组长度,会改变原数组。
方法二:push 后增
let arr = [1];
arr.push(2); // [1,2]
作用:向数组尾部添加元素。
返回值:返回添加后的新数组长度,会改变原数组。
- 删除
方法一: shift 前删
let arr = [1,2,3];
arr.shift(); // 1
console.log(arr); // [2,3]
作用:删除数组头部的元素。
返回值:返回删除的元素,会改变原数组。
方法二: pop后删
let arr = [1,2,3];
arr.pop(); // 3
console.log(arr); // [1,2]
作用:删除数组尾部的元素。
返回值:返回删除的元素,会改变原数组。
- 替换
方法一: splice 截取
let arr = [1,2,3,4];
arr.splice(0,1); // [1] 代表从0开始删除一个元素
console.log(arr); // [2,3,4]
arr.splice(1,2,9); // [2,3] 从索引1开始删除两个元素并替换成9
console.log(arr); // [1.9.4]
arr.splice(3,0,10); // [] 从索引3开始,不删除元素,并添加元素10
console.log(arr); // [1,2,3,4,10]
作用:数组任意位置的元素替换、插入、删除操作。
返回值:返回删除元素组成的新数组,回改变原数组。
- 拼接
方法一: push
let arr1 = [1,2];
let arr2 = [3,4];
arr1.push(arr2);
console.log(arr1); // [1,2,[3,4]]
方法二: concat
let arr1 = [1,2];
let arr2 = [3,4];
let arr3 = arr1.concat(arr2);
console.log(arr3) // [1,2,3,4]
作用:将arr2的所有元素展开拼接在arr1后。
返回值:返回拼接后的副本,不会改变原数组。
- 查找
方法一: indexOf
let arr = [1,2,3,1,5];
let index = arr.indexOf(1);
console.log(index); // 0
作用:返回元素在数组中首次出现的下标,如果找不到,返回-1;
返回值:查找到的下标,不会改变原数组。
方法二:lastIndexOf
let arr = [1,2,3,2,1,2];
let index = arr.lastIndexOf(1);
console.log(index); // 4
作用:返回元素在数组中最后一次出现的下标,如果找不到,返回-1;
返回值:查找到的下标,不会改变原数组。
- 排序
方法一:sort
let arr = [5,7,3,9,1,6];
arr.sort();// [1,3,5,6,7,9]
作用:将数组按照默认排序方式进行排序。
返回值:返回排序好的数组,不影响原数组。
方法二: reverse
let arr = [5,7,3,9,1,6];
arr.reverse();// [6,1,9,3,7,5]
作用:将数组逆序排列。
返回值:返回逆序后的数组,会改变原数组。
- 转换
方法一:toString 转换为字符串
let arr = [1,2];
let str = arr.toString();
console.log(str); // "1,2"
作用:将数组中的元素以字符串的方式输出。
返回值:返回转换好的字符串,不会改变原数组。
方法二: join
let arr = [1,2,3];
let str1 = arr.join(".");
console.log(str1); //"1.2.3"
let str2 = arr.join("$");
console.log(str2); //"1$2$3"
作用:使用特定的分隔符将数组中的元素连接起来,并以字符串的方式输出。
返回值:返回转换好的字符串。不会改变原数组。
数组的优劣和操作的时间复杂度
优点缺点:
- 优点:更新查找快,由于数组是线性查存储,所有只需要给我们想要的元素下标,就可以方便的更新元素和查找元素。
- 缺点:增删慢,还是因为数组的线性存储,举个例子,比如说我们的书桌上堆放着一摞书,我想要拿第 5 本,我需要动前 4 本才可以拿到想要的。如果书我想把一本书放在中间位置,同样需要动中间位置之前的所有书才可以。”
- 时间复杂度:
至于时间复杂度嘛。由于更新查找的时候只需要提供下标,所以时间复杂度是O(1)。增加和删除的时候需要改动数组中的其他元素,所以时间复杂度是O(n)。
将数组乱序
function shuffle(arr) {
for (let i=arr.length-1; i>=0; i--) {
let rIndex = Math.floor(Math.random()*(i+1));
let temp = arr[rIndex];
arr[rIndex] = arr[i];
arr[i] = temp;
}
return arr;
}
- 得到数组最后一个元素的下标,然后开始逆序数组;
- 获得从 0 到当前元素的随机元素,并让两个元素交换位置;
- 4、5、6 行为元素交换方式,此方式需要创建中间变量,用来保存当前元素;
- 由于数组是引用类型,所以我们在改变传入参数arr的同时也会修改原本的数组。此时,直接将 arr 返回,可以得到经过处理的乱序的数组。
简单方案:
arr.sort(function(a,b){ return Math.random()>.5 ? -1 : 1;});
sort() 本意为排序函数,可根据其特性创建乱序数组。方法可直接调用,不传入任何参数,也可传入一个比较函数作为参数。
- 不传参数
此方法不传入参数时,会使用默认排序方式。先调用每个元素的toString() 方法,然后按照转换后字符串的 Unicode 编码来进行排序。
[1, 2, 3, 15, 22, 33].sort() // 1, 15, 2, 22, 3, 33
- 传入函数参数 (参数只能是函数)
传入函数参数,可以让调用者按照自己的意愿对元素进行排序。
// 函数参数的实现
function compare(value1, value2) {
if (value1 < value2) {
return 1;
}
if (value1 > value2) {
return -1
}
return 0
}
如果函数返回 1 排序后 value1 会位于 value2 之后
返回 -1 排序后 value1 会在 value2 之前;
返回 0 则说明两个元素相等,排序后位置不会发生变化。
上述函数可改写为:
function compare(value1, value2) {
return value1 < value2 ? 1 : -1;
}
若 value1 和 value2 的比较结果是随机的(如举例所示),会出现数组乱序的现象。
调用 sort 方法,在排序过程中,每次执行会取得随机浮点数。根据随机数来调整每个元素的位置。最后得到乱序之后的数组。