前言
Hello,大家好,这里是成功在家隔离四天的GIS宇宙,最近趁着不怎么忙碌,可以好好学习一下算法和数据结构了,本科期间基本学了和没学一样,所以接下来会出一个关于JavaScript算法和数据结构的专栏,本人水平有限,也是边学边记录,如果你喜欢这个专栏的话,可以点个赞,蟹蟹~
今天首先对JavaScript最基础的数组进行介绍,下一篇会介绍栈,感兴趣的赶紧关注我吧~
数组创建
- new 关键字
- 中括号
let daysOfWeek = new Array(); // {1}
daysOfWeek = new Array(7); // {2}
daysOfWeek = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); // {3}
let daysOfWeek = []
let daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', ]
添加元素
1.尾部插入push
daysOfWeek.push(123)
2.头部插入unshift
头部操作,首先将 i 元素赋值给 i+1,然后在索引0的位置插入新值
daysOfWeek.unshift(-1)
如果自己写的话,则为数组右移,腾出头部位置,还多申明了一个数组位置
Array.prototype.insertFirstPosition = function(value) {
for (let i = this.length; i >= 0; i--) {
this[i] = this[i - 1];
}
this[0] = value;
};
numbers.insertFirstPosition(-1);
删除元素
1.尾部删除
daysOfWeek.pop()
2.头部删除
daysOfWeek.shift()
将所有元素都赋值给前一个元素,并删除最后一个值,length最后变为16。
如果直接左移(如下述),最后一个元素会报错变成undefined。
for (let i = 0; i < numbers.length; i++) {
numbers[i] = numbers[i + 1];
}
任意位置添加删除元素
numbers.splice(5, 0, 2, 3, 4);
splice第一个参数表示想要删除或插入元素的索引值,即数组的位置,第二个是删除的个数,0表示不删除,2,3,4表示将2,3,4依次插入到数组中。
numbers.splice(5, 3, 2, 3, 4);
上述代码表示,从5索引开始删除3个元素,并插入后面的2,3,4数字。
多维数组
JavaScript 只支持一维数组,并不支持矩阵。但是,我们可以用数组套数组,实现矩阵或任一多维数组。代码也可以写成如下这样。
let averageTemp = [];
// day 1
averageTemp[0] = [];
averageTemp[0][0] = 72;
averageTemp[0][1] = 75;
averageTemp[0][2] = 79;
averageTemp[0][3] = 79;
averageTemp[0][4] = 81;
averageTemp[0][5] = 81;
// day 2
averageTemp[1] = [];
averageTemp[1][0] = 81;
averageTemp[1][1] = 79;
averageTemp[1][2] = 75;
averageTemp[1][3] = 75;
averageTemp[1][4] = 73;
averageTemp[1][5] = 73;
使用console.table()可以以表格的形式打印出来:
数组方法
除了上述提到的方法,Js数组还提供了很多方法,常用如下:
1.数组合并
const zero = 0;
const positiveNumbers = [1, 2, 3];
const negativeNumbers = [-3, -2, -1];
let numbers = negativeNumbers.concat(zero, positiveNumbers);
// [-3, -2, -1, 0, 1, 2, 3]
2.迭代器
- every
- some
- forEach
- map
- filter
- reduce
function isEven(x) {
// 如果 x 是 2 的倍数,就返回 true
console.log(x);
return x % 2 === 0 ? true : false;
}
// ES2015(ES6)简写: const isEven = x => x % 2 === 0;
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1. every : 当返回false的时候停止
numbers.every(isEven);
// 1
2. some : 当返回true的时候停止
numbers.some(isEven);
// 1
// 2
3. forEach : 相当于for,无返回值
numbers.forEach(x => console.log(x % 2 === 0));
// false true false true ...
4. map :相当于for,返回一个包含所有返回值的数组
const myMap = numbers.map(isEven);
//
[
false, true, false,
true, false, true,
false, true, false,
true, false, true,
false, true, false
]
5. filter :返回满足条件的值(即返回true的值),
const evenNumbers = numbers.filter(isEven);
//
[
2, 4, 6, 8,
10, 12, 14
]
6. reduce :接收一个有如下四个参数的函数:previousValue、currentValue、index和array。index和array是可选的参数。
函数式编程:返回数组的累加
const reduceNumbers = numbers.reduce((previous, current) => previous + current);
// 120
3.ES6新方法
for of 循环迭代
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
for (const n of numbers) {
console.log(n % 2 === 0 ? 'even' : 'odd');
}
@@iterator对象
通过Symbol.iterator访问并执行函数,返回iterator对象,iterator对象有个next函数,每次执行,返回结果:{value: 2, done: false},通过.value访问值,done的值为false意味着还有可迭代的值。
let iterator = numbers[Symbol.iterator]();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
console.log(iterator.next().value); // 4
console.log(iterator.next().value); // 5
也可以通过for of来循环输出
iterator = numbers[Symbol.iterator]();
for (const n of iterator) {
console.log(n);
}
entries、keys和values方法
entries方法返回包含键值对的@@iterator;使用集合、字典、散列表等数据结构时,能够取出键值对是很有用。
let aEntries = numbers.entries(); // 得到键值对的迭代器
console.log(aEntries.next().value); // [0, 1] - 位置 0 的值为 1
console.log(aEntries.next().value); // [1, 2] - 位置 1 的值为 2
console.log(aEntries.next().value); // [2, 3] - 位置 2 的值为 3
// 也可用for of 迭代
aEntries = numbers.entries();
for (const n of aEntries) {
console.log(n);
}
keys方法返回包含数组索引的@@iterator,value表示元素的索引,done属性的值为false,就意味着还有可迭代的值。
一旦没有可迭代的值,aKeys.next()就会返回一个value属性为undefined、done属性为true的对象。
const aKeys = numbers.keys(); // 得到数组索引的迭代器
console.log(aKeys.next()); // {value: 0, done: false }
console.log(aKeys.next()); // {value: 1, done: false }
console.log(aKeys.next()); // {value: 2, done: false }
values方法返回包含数组的值的@@iterator。
const aValues = numbers.values();
console.log(aValues.next()); // {value: 1, done: false }
console.log(aValues.next()); // {value: 2, done: false }
console.log(aValues.next()); // {value: 3, done: false }
Array.from 方法
Array.from可以根据已有数组创建一个新数组,也可根据函数过滤。
let numbers2 = Array.from(numbers);
[
1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12,
13, 14, 15
]
let evens = Array.from(numbers, x => (x % 2 == 0));
[
false, true, false,
true, false, true,
false, true, false,
true, false, true,
false, true, false
]
Array.of 方法
Array.of方法根据传入的参数创建一个新数组。以下面的代码为例。
let numbers3 = Array.of(1);
let numbers4 = Array.of(1, 2, 3, 4, 5, 6);
// 它和下面这段代码的效果一样。
let numbers3 = [1];
let numbers4 = [1, 2, 3, 4, 5, 6];
// 也可以用该方法复制已有的数组,如下所示,(...)可以展开数组。
let numbersCopy = Array.of(...numbers4);
fill 方法
fill方法用静态值填充数组。以下面的代码为例。
let numbersCopy = Array.of(1, 2, 3, 4, 5, 6);
// numbersCopy数组的length是 6,也就是有 6 个位置。再看下面的代码。
numbersCopy.fill(0);
// numbersCopy数组所有位置上的值都会变成 0([0, 0, 0, 0, 0, 0])。我们还可以指定开始填充的索引,如下所示。
numbersCopy.fill(2, 1);
// 上面的例子里,数组中从 1 开始的所有位置上的值都是 2([0, 2, 2, 2, 2, 2])。 同样,我们也可以指定结束填充的索引。
numbersCopy.fill(1, 3, 5);
// 在上面的例子里,我们会把 1 填充到数组索引 3 到 5 的位置(不包括 3 和 5),得到的数组为[0, 2, 2, 1, 1, 2]。
// 创建数组并初始化值的时候,fill方法非常好用,就像下面这样。
let ones = Array(6).fill(1);
// 上面的代码创建了一个长度为 6、所有值都是 1 的数组([1, 1, 1, 1, 1, 1])。
copyWithin 方法
copyWithin方法复制数组中的一系列元素到同一数组指定的起始位置。
array.copyWithin(target, start,end)
target为指定起始位置(必须),start为元素复制的起始索引位置,end为停止复制的索引位置 (默认为array .length)
let copyArray = [1, 2, 3, 4, 5, 6];
// 假如我们想把 4、5、6 三个值复制到数组前三个位置,得到[4, 5, 6, 4, 5, 6]这个数组,可以用下面的代码达到目的。
copyArray.copyWithin(0, 3);
// 假如我们想把 4、5 两个值(在位置 3 和 4 上)复制到位置 1 和 2,可以这样做:
copyArray = [1, 2, 3, 4, 5, 6];
copyArray.copyWithin(1, 3, 5);
// 这种情况下,会把从位置 3 开始到位置 5 结束(不包括 3 和 5)的元素复制到位置 1,结果是得到数组[1, 4, 5, 4, 5, 6]。
4.排序
反序输出数组numbers(它本来的排序是1, 2, 3, 4, …, 15)
numbers.reverse();
输出numbers的话就会看到[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],此时使用sort方法
numbers.sort();
结果会是[1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9]。看起来不大对,是吧?这是因为sort方法在对数组做排序时,把元素默认成字符串进行相互比较。
我们可以传入自己写的比较函数。因为数组里都是数,所以可以像下面这样写。
numbers.sort((a, b) => a - b);
b大于a时,这段代码会返回负数,反之则返回正数。如果相等的话,就会返回 0。也就是说返回的是负数,就说明a比b小,这样sort就能根据返回值的情况对数组进行排序。
之前的代码也可以表示成如下这样,会更清晰一些。
function compare(a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
// a 必须等于 b
return 0;
}
numbers.sort(compare);
① 自定义排序
const friends = [
{
name: 'John', age: 30 },
{
name: 'Ana', age: 20 },
{
name: 'Chris', age: 25 }, // ES2017 允许存在尾逗号
];
function comparePerson(a, b) {
if (a.age < b.age) {
return -1;
}
if (a.age > b.age) {
return 1;
}
return 0;
}
console.log(friends.sort(comparePerson));
//
[
{
name: 'Ana', age: 20 },
{
name: 'Chris', age: 25 },
{
name: 'John', age: 30 }
]
② 字符串排序
假如有这样一个数组。
let names = ['Ana', 'ana', 'john', 'John']; console.log(names.sort());
你猜会输出什么?答案如下所示。
["Ana", "John", "ana", "john"]
既然a在字母表里排第一位,为何ana却排在了John之后呢?这是因为 JavaScript 在做字
符比较的时候,是根据字符对应的 ASCII 值来比较的。例如,A、J、a、j对应的 ASCII 值分别是65、74、97、106。虽然a在字母表里是最靠前的,但J的 ASCII 值比a的小,所以排在了a前面。
更多关于 ASCII 表的信息,请访问 http://www.asciitable.com/。
如果使用sort来忽略大小写:
names = ['Ana', 'ana', 'john', 'John']; // 重置数组的初始状态
console.log(names.sort((a, b) => {
if (a.toLowerCase() < b.toLowerCase()) {
return -1;
}
if (a.toLowerCase() > b.toLowerCase()) {
return 1;
}
return 0;
}));
// ['Ana', 'ana', 'john', 'John']
你会发现数组没有变化,因为都变成小写来比较,所以当两者相同时,保持了原有的顺序。
如果希望小写字母排在前面,那么需要使用localeCompare方法。
names.sort((a, b) => a.localeCompare(b));
最后输出[ ‘ana’, ‘Ana’, ‘john’, ‘John’ ]
假如对带有重音符号的字符做排序的话,也可以用localeCompare来实现。
const names2 = ['Maève', 'Maeve'];
console.log(names2.sort((a, b) => a.localeCompare(b)));
最后输出的结果将是[“Maeve”, “Maève”]。
5.搜索
indexOf方法返回与参数匹配的第一个元素的索引;
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
console.log(numbers.indexOf(10));
// 9
console.log(numbers.indexOf(100));
// -1 没找到
lastIndexOf返回与参数匹配的最后一个元素的索引。
numbers.push(10);
console.log(numbers.lastIndexOf(10));
// 15
console.log(numbers.lastIndexOf(100));
// -1
① ES6——find和findIndex方法
find和findIndex方法接收一个回调函数,搜索一个满足回调函数条件的值。下面的例子
里,我们要从数组里找一个 13 的倍数。find和findIndex的不同之处在于,find方法返回第一个满足条件的值,findIndex方法则返回这个值在数组里的索引。如果没有满足条件的值,find会返回undefined,而findIndex返回-1。
let numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
function multipleOf13(element, index, array) {
return (element % 13 == 0);
}
console.log(numbers.find(multipleOf13));
// 13
console.log(numbers.findIndex(multipleOf13));
// 12
② ES7——includes方法
如果数组里存在某个元素,includes方法会返回true,否则返回false。使用includes
方法的例子如下。
console.log(numbers.includes(15)) // true
console.log(numbers.includes(20)) // false
可给includes方法传入一个起始索引,搜索会从索引指定的位置开始。
let numbers2 = [7,6,5,4,3,2,1];
console.log(numbers2.includes(4,5));// false,从第四位开始搜索,因此错过了5
6.输出字符串
① toString()方法
console.log(numbers.toString()); //1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
② join()方法
const numbersString = numbers.join('-');
console.log(numbersString); // '1-2-3-4-5-6-7-8-9-10-11-12-13-14-15'
7.官方文档
类型数组
与C 和 Java 等其他语言不同,JavaScript 数组不是强类型的,因此它可以存储任意类型的
数据。类型数组则用于存储单一类型的数据。它的语法是let myArray = new TypedArray
(length),其中TypedArray需替换为下表所列之一。
let length = 5;
let int16 = new Int16Array(length);
for (let i=0; i<length; i++){
int16[i] = i+1;
}
console.log(int16);
使用 WebGL API、进行位操作、处理文件和图像时,类型数组都可以大展拳脚。它用起来和普通数组毫无二致,本章所学的数组方法和功能都可以用于类型数组。https://www.html5rocks.com/en/tutorials/webgl/typed_arrays/是一个很好的教程,讲解了如何使用类型数组处理二进制数据,以及它在实际项目中的应用。
TypeScript中的数组
TypeScript 会在编译时进行类型检测,来确保只对所有值都属于相同数据类型的数组进行操作。
根据类型推断,TypeScript 能够理解numbers数组的声明和const numbers: number[]是一样的。
interface Person {
name: string;
age: number;
}
// const friends: {name: string, age: number}[]; 与下述方式一样
const friends = [
{
name: 'John', age: 30 },
{
name: 'Ana', age: 20 },
{
name: 'Chris', age: 25 }
];
function comparePerson(a: Person, b: Person) {
// comparePerson 函数的内容
}
总结
本文学习了JavaScript数组的基本用法,为下篇文章——栈做铺垫,也简单介绍了Typescript的数组,自己在学习的过程中也是学到了一些平时不怎么用的新东西,希望对你也有些帮助,这里是GIS宇宙,我们下期再见。
参考文献:
Array - JavaScript | MDN (mozilla.org)
学习JavaScript数据结构与算法第三版 Learning JavaScript Data Structures and Algorithms 3rd Edition ([巴西]格罗纳(LoianeGroner), 孙晓博, 邓钢, 吴双, 陈迪, 袁源) (z-lib.org)
本人其他平台账号:
- 微信公众号:GIS宇宙
- CSDN:GIS_宇宙
- 知乎:GIS宇宙
- 掘金:GIS宇宙