【重温基础】10.数组

47次阅读

共计 9922 个字符,预计需要花费 25 分钟才能阅读完成。

本文是 重温基础 系列文章的第十篇。今日感受:平安夜,多棒。
系列目录:

【复习资料】ES6/ES7/ES8/ES9 资料整理(个人整理)
【重温基础】1. 语法和数据类型
【重温基础】2. 流程控制和错误处理
【重温基础】3. 循环和迭代
【重温基础】4. 函数
【重温基础】5. 表达式和运算符
【重温基础】6. 数字
【重温基础】7. 时间对象
【重温基础】8. 字符串
【重温基础】9. 正则表达式

本章节复习的是 JS 中的数组,以索引进行排序。
前置知识:数组是一个有序的数据集合,使用数组名称和索引进行访问。
let arr = [1,2,3];
arr[0] = 1;
在 JavaScript 中数组没有明确数据类型。
let arr = [1, ‘hi’, undefined, fun()];
1. 创建数组
创建数组方法有 3 种:
let arr = new Array(ele1, ele2, ele3, …, eleN);
let arr = Array(ele1, ele2, ele3, …, eleN);
let arr = [ele1, ele2, ele3, …, eleN];
上面是已知数组元素,另外一种还有创建一个长度不为 0,且有没有任何元素的数组:
let len = 5;

let arr = new Array(len); // 方法 1
let arr = Array(len); // 方法 2
let arr = []; // 方法 3
arr.length = len;
若传入的数组长度不是整数,则报错:
let arr = new Array(3.5);
let arr = Array(3.5);
let arr = [];
arr.length = 3.5;
//Uncaught RangeError: Invalid array length
其中要注意这两种创建方法是不同的:
let arr1 = new Array(4); // [empty × 4]
let arr2 = [4]; // [4]
for(let k in arr1){
console.log(k);
} // undefined
for(let k in arr2){
console.log(k);
} // 0
2. 使用数组
2.1 简单使用
获取数组指定位置的值:
let a = [1,2,5];
a[0]; // 1
a[2]; // 5
a[3]; // undefined
获取数组长度:
let a = [1,2,5];
a.length; // 3
a[“length”]; // 3
设置数组指定位置的值:
let a = [1,2,5];
a[0] = 9;
a[2] = 99;
a[3] = 999;
2.2 理解数组 length

数组的索引值是从 0 开始,即上面数组索引 0 的是 1, 索引 1 的值是 2,依次下去。
数组 length 永远返回的是数组最后一个元素的索引加 1。
可通过 arr.length = 0 来清空数组。
可通过 arr.length = len 来设置数组长度。

2.3 遍历数组
遍历数组就是以某种方法处理数组的每个元素,简单如下:
使用 for 循环:
let arr = [“pingan”, “leo”, “robin”];
for (let i = 0; i<arr.length; i++){
// 处理元素的操作
console.log(` 第 ${i}个元素是:${arr[i]};`)
}
// 第 0 个元素是:pingan;
// 第 1 个元素是:leo;
// 第 2 个元素是:robin;
使用 for…in:
let arr = [“pingan”, “leo”, “robin”];
for(let i in arr){
console.log(` 第 ${i}个元素是:${arr[i]};`)
}
// 第 0 个元素是:pingan;
// 第 1 个元素是:leo;
// 第 2 个元素是:robin;
使用 forEach:
arr.forEach(callback) 接收一个回调方法。callback(val, index, array) : 接收三个参数:
* `val` : 当前处理的元素;
* `index` : 当前处理的元素的索引;
* `array` : 正在处理的数组;

可参考 MDN Array.prototype.forEach 的详细介绍。
let arr = [“pingan”, “leo”, “robin”];
arr.forEach(function(val, i, array){
console.log(` 第 ${i}个元素是:${val};`)
})
3. 数组方法(访问和修改)

方法名称
方法介绍

concat()
连接两个或更多的数组,并返回结果。

join()
把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。

pop()
删除并返回数组的最后一个元素

push()
向数组的末尾添加一个或更多元素,并返回新的长度。

reverse()
颠倒数组中元素的顺序。

shift()
删除并返回数组的第一个元素

slice()
从某个已有的数组返回选定的元素

sort()
对数组的元素进行排序

splice()
删除元素,并向数组添加新元素。

toSource()
返回该对象的源代码。

toString()
把数组转换为字符串,并返回结果。

toLocaleString()
把数组转换为本地数组,并返回结果。

unshift()
向数组的开头添加一个或更多元素,并返回新的长度。

valueOf()
返回数组对象的原始值

indexOf()
在数组中搜索指定元素并返回第一个匹配的索引

lastIndexOf()
在数组中搜索指定元素并返回最后一个匹配的索引

可参考 W3school JavaScript Array 对象 的详细介绍。
3.1 concat()
连接两个或更多的数组,并返回一个新数组。
语法:
arr.concat(a1, a2, …, an);
参数:
arr:目标数组;a1,a2,…,an:需要合并的元素;
let a1 = [1,2,3];
let a2 = [9,99,999];
let a = a1.concat(a2);
// [1, 2, 3, 9, 99, 999]
3.2 join()
使用指定分隔符,连接两个或多个数组的元素,返回一个字符串。
语法:
arr.join(sep);
参数:
arr:目标数组;sep:连接的分隔符,默认值为“,”;
let arr = [“pingan”, “leo”, “robin”];
arr.join(); // “pingan,leo,robin”
arr.join(“”); // “pinganleorobin”
arr.join(“,”); // “pingan,leo,robin”
3.3 pop()和 push()

pop(): 删除并返回数组最后一个元素,改变原数组。

push(item): 向数组末尾添加一个或多个元素,改变原数组,返回新的数组长度。

方便记忆和理解:两个都是从数组末尾操作,pop()是删除最后一个元素,push()是向最后一位添加新的元素。
let arr = [“pingan”, “leo”];
let a1 = arr.pop(); // “leo”
let a2 = arr.push(“robin”,”hi”); // 3
arr; // [“pingan”, “robin”, “hi”]
3.4 shift()和 unshift()

shift(): 删除并返回数组第一个元素,改变原数组。

unshift(item): 向数组头部添加一个或多个元素,改变原数组,返回新的数组长度。

方便记忆和理解:两个都是从数组头部操作,shift()是删除第一个元素,unshift()是向第一位添加新的元素。
let arr = [“pingan”, “leo”];
let a1 = arr.shift(); // “pingan”
let a2 = arr.unshift(“robin”,”hi”); // 3
arr; // [“robin”, “hi”, “leo”]
3.5 reverse()
颠倒数组中元素的顺序,改变原数组。
let arr = [1, 2, 3, 4];
arr.reverse(); // [4, 3, 2, 1]
3.6 slice()
用于提取数组中一个片段,作为新数组返回。slice(start[,end]): 接收 2 个参数:

start: 必需,指定起始索引,若负数则从数组最后开始算起,- 1 为倒数第一位,- 2 为倒数第二位,以此类推。

end:可选,指定结束索引,若没传则表示到数组结束。

注意:end 若有指定的话,是不包含 end 索引上的值。
let arr = [1, 2, 3, 5, 6];
let a1 = arr.slice(2); // [3, 5, 6]
let a2 = arr.slice(2,3); // [3]
3.7 splice()
从数组中删除指定索引开始的项目,然后返回被删除的项目。
语法:
arr.splice(index, num, a1, a2,…,an);
参数:
index: 必需,起始位置的索引,若负数则从数组最后开始算起;num:必需,删除的数量,若为 0 则不删除;a1,a2,…an:可选,为数组添加的元素;
let arr = [1, 2, 3, 4];
let a = arr.splice(1, 2, “hi”, “leo”);
// a =>  [2, 3]
// arr => [1, “hi”, “leo”, 4]
3.8 sort()
对数组的元素进行排序,改变原数组。可接受一个回调方法作为比较函数,来决定排序方式。比较函数应该具有两个参数 a 和 b,返回值如下:若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。若 a 等于 b,则返回 0。若 a 大于 b,则返回一个大于 0 的值。
let a1 = [1,3,6,9,10];
a1.sort(); // [1, 10, 3, 6, 9]
a1.sort(function(a,b){
return a > b ? 1 : a < b ? -1 : 0;
}) // [1, 3, 6, 9, 10]
3.9 indexOf()和 lastIndexOf()
两者都是在数组搜索指定元素,只是 indexOf()返回的是搜索到的第一个元素的索引,而 lastIndexOf()返回的是搜索到的最后一个元素的索引。语法:indexOf(ele[,start])和 lastIndexOf(ele[,start]); 参数:

ele: 需要搜索的元素。

start: 开始搜索的索引。

let arr = [“hh1”, “hh2”, “hh2”, “hh2”, “hh3”, “hh4”];
let a1 = arr.indexOf(“hh2”); // 1
let a2 = arr.lastIndexOf(“hh2”); // 3
let a3 = arr.indexOf(“hh2”,2); // 2
4. 数组方法(迭代)

方法名称
方法介绍

forEach()
为数组中的每个元素执行一次回调函数。

every()
如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false。

some()
如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false。

filter()
将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回。

map()
返回一个由回调函数的返回值组成的新数组。

reduce()
从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。

reduceRight()
从右到左为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。

以下是 ES6 规范新增的数组方法:

方法名称
方法介绍

keys()
返回一个数组迭代器对象,该迭代器会包含所有数组元素的键。

values()
返回一个数组迭代器对象,该迭代器会包含所有数组元素的值。

entries()
返回一个数组迭代器对象,该迭代器会包含所有数组元素的键值对。

find()
找到第一个满足测试函数的元素并返回那个元素的值,如果找不到,则返回 undefined。

findIndex()
找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回 -1。

可参考 MDN Array 的详细介绍。
4.1 forEach()
对数组的每个元素执行一次提供的函数。
语法:arr.forEach(callback)。
参数:callback(val, index, arr) : 需要执行的函数,接收三个参数:

val : 正在处理的当前元素;

index : 可选,正在处理的当前元素的索引;

arr : 可选,正在操作的数组;

let a = [1,3,5,7];
a.forEach(function(val, index, arr){
arr[index] = val * 2
})
a ; // [2, 6, 10, 14]
4.2 every()
测试数组的所有元素是否都通过了指定函数的测试。语法:arr.every(callback)。
参数:callback(val, index, arr) : 需要执行的函数,接收三个参数:

val : 正在处理的当前元素;

index : 可选,正在处理的当前元素的索引;

arr : 可选,正在操作的数组;

返回值:若都通过返回 true,否则返回 false。
let a = [1, “”, “aa”, 13, 6];
let res = a.every(function(val, index, arr){
return typeof val == “number”;
})
res;// false

let b = [1, 2, 3];
let r = b.every(function(val, index, arr){
return typeof val == “number”;
})
r; // true
4.3 some()
测试数组中的某些元素是否通过由提供的函数实现的测试。语法:arr.some(callback)。
参数:callback(val, index, arr) : 需要执行的函数,接收三个参数:

val : 正在处理的当前元素;

index : 可选,正在处理的当前元素的索引;

arr : 可选,正在操作的数组;

返回值:若有一个通过返回 true,否则返回 false。
let a = [1, “”, “aa”, 13, 6];
let res = a.some(function(val, index, arr){
return typeof val == “number”;
})
res;// true

let b = [1, 2, 3];
let r = b.some(function(val, index, arr){
return typeof val == “number”;
})
r; // true
4.4 filter()
将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回。
语法:arr.filter(callback)。
参数:callback(val, index, arr) : 需要执行的函数,接收三个参数:

val : 正在处理的当前元素;

index : 可选,正在处理的当前元素的索引;

arr : 可选,正在操作的数组;

返回值:一个返回通过测试的元素的数组,若都没有则返回空数组。
let a = [1, “”, “aa”, 13, 6];
let res = a.filter(function(val, index, arr){
return typeof val == “number”;
})
res;//[1, 13, 6]
4.5 map()
传入一个操作函数,对每个元素执行此方法,并返回一个执行后的数组。
语法:arr.map(callback)。
参数:callback(val, index, arr) : 需要执行的函数,接收三个参数:

val : 正在处理的当前元素;

index : 可选,正在处理的当前元素的索引;

arr : 可选,正在操作的数组;

返回值:一个新数组,每个元素都是回调函数的结果。
let a = [1, 3, 5];
let b = a.map(function(val, index, arr){
return val + 2;
})
b; //[3, 5, 7]
5. 数组的拓展(ES6)
5.1 拓展运算符
拓展运算符使用 (…),类似 rest 参数的逆运算,将数组转为用(,) 分隔的参数序列。
console.log(…[1, 2, 3]); // 1 2 3
console.log(1, …[2,3], 4); // 1 2 3 4
拓展运算符主要使用在函数调用。
function f (a, b){
console.log(a, b);
}
f(…[1, 2]); // 1 2

function g (a, b, c, d, e){
console.log(a, b, c, d, e);
}
g(0, …[1, 2], 3, …[4]); // 0 1 2 3 4
若拓展运算符后面是个空数组,则不产生效果。
[…[], 1]; // [1]
替代 apply 方法
// ES6 之前
function f(a, b, c){…};
var a = [1, 2, 3];
f.apply(null, a);

// ES6 之后
function f(a, b, c){…};
let a = [1, 2, 3];
f(…a);

// ES6 之前
Math.max.apply(null, [3,2,6]);

// ES6 之后
Math.max(…[3,2,6]);
拓展运算符的运用

(1)复制数组:
通常我们直接复制数组时,只是浅拷贝,如果要实现深拷贝,可以使用拓展运算符。
// 通常情况 浅拷贝
let a1 = [1, 2];
let a2 = a1;
a2[0] = 3;
console.log(a1,a2); // [3,2] [3,2]

// 拓展运算符 深拷贝
let a1 = [1, 2];
let a2 = […a1];
// let […a2] = a1; // 作用相同
a2[0] = 3;
console.log(a1,a2); // [1,2] [3,2]

(2)合并数组:
注意,这里合并数组,只是浅拷贝。
let a1 = [1,2];
let a2 = [3];
let a3 = [4,5];

// ES5
let a4 = a1.concat(a2, a3);

// ES6
let a5 = […a1, …a2, …a3];

a4[0] === a1[0]; // true
a5[0] === a1[0]; // true

(3)与解构赋值结合:
与解构赋值结合生成数组,但是使用拓展运算符需要放到参数最后一个,否则报错。
let [a, …b] = [1, 2, 3, 4];
// a => 1 b => [2,3,4]

let [a, …b] = [];
// a => undefined b => []

let [a, …b] = [“abc”];
// a => “abc” b => []
5.2 Array.from()
将 类数组对象 和 可遍历的对象,转换成真正的数组。
// 类数组对象
let a = {
‘0’:’a’,
‘1’:’b’,
length:2
}
let arr = Array.from(a);

// 可遍历的对象
let a = Array.from([1,2,3]);
let b = Array.from({length: 3});
let c = Array.from([1,2,3]).map(x => x * x);
let d = Array.from([1,2,3].map(x => x * x));
5.3 Array.of()
将一组数值,转换成数组,弥补 Array 方法参数不同导致的差异。
Array.of(1,2,3); // [1,2,3]
Array.of(1).length; // 1

Array(); // []
Array(2); // [,] 1 个参数时,为指定数组长度
Array(1,2,3); // [1,2,3] 多于 2 个参数,组成新数组
5.4 find()和 findIndex()
find()方法用于找出第一个符合条件的数组成员,参数为一个回调函数,所有成员依次执行该回调函数,返回第一个返回值为 true 的成员,如果没有一个符合则返回 undefined。
[1,2,3,4,5].find(a => a < 3); // 1
回调函数接收三个参数,当前值、当前位置和原数组。
[1,2,3,4,5].find((value, index, arr) => {
// …
});
findIndex()方法与 find()类似,返回第一个符合条件的数组成员的位置,如果都不符合则返回 -1。
[1,2,3,4].findIndex((v,i,a)=>{
return v>2;
}); // 2
5.5 fill()
用于用指定值填充一个数组,通常用来初始化空数组,并抹去数组中已有的元素。
new Array(3).fill(‘a’); // [‘a’,’a’,’a’]
[1,2,3].fill(‘a’); // [‘a’,’a’,’a’]
并且 fill()的第二个和第三个参数指定填充的起始位置和结束位置。
[1,2,3].fill(‘a’,1,2);// [1, “a”, 3]
5.6 entries(),keys(),values()
主要用于遍历数组,entries()对键值对遍历,keys()对键名遍历,values()对键值遍历。
for (let i of [‘a’, ‘b’].keys()){
console.log(i)
}
// 0
// 1

for (let e of [‘a’, ‘b’].values()){
console.log(e)
}
// ‘a’
// ‘b’

for (let e of [‘a’, ‘b’].entries()){
console.log(e)
}
// 0 ‘a’
// 1 ‘b’
5.7 includes()
用于表示数组是否包含给定的值,与字符串的 includes 方法类似。
[1,2,3].includes(2); // true
[1,2,3].includes(4); // false
[1,2,NaN].includes(NaN); // true
第二个参数为起始位置,默认为 0,如果负数,则表示倒数的位置,如果大于数组长度,则重置为 0 开始。
[1,2,3].includes(3,3); // false
[1,2,3].includes(3,4); // false
[1,2,3].includes(3,-1); // true
[1,2,3].includes(3,-4); // true
5.8 flat(),flatMap()
flat()用于将数组一维化,返回一个新数组,不影响原数组。默认一次只一维化一层数组,若需多层,则传入一个整数参数指定层数。若要一维化所有层的数组,则传入 Infinity 作为参数。
[1, 2, [2,3]].flat(); // [1,2,2,3]
[1,2,[3,[4,[5,6]]]].flat(3); // [1,2,3,4,5,6]
[1,2,[3,[4,[5,6]]]].flat(‘Infinity’); // [1,2,3,4,5,6]
flatMap()是将原数组每个对象先执行一个函数,在对返回值组成的数组执行 flat()方法,返回一个新数组,不改变原数组。flatMap()只能展开一层。
[2, 3, 4].flatMap((x) => [x, x * 2]);
// [2, 4, 3, 6, 4, 8]
6. 数组的拓展(ES7)
6.1 Array.prototype.includes()方法
includes()用于查找一个值是否在数组中,如果在返回 true,否则返回 false。
[‘a’, ‘b’, ‘c’].includes(‘a’); // true
[‘a’, ‘b’, ‘c’].includes(‘d’); // false
includes()方法接收两个参数,搜索的内容和开始搜索的索引,默认值为 0,若搜索值在数组中则返回 true 否则返回 false。
[‘a’, ‘b’, ‘c’, ‘d’].includes(‘b’); // true
[‘a’, ‘b’, ‘c’, ‘d’].includes(‘b’, 1); // true
[‘a’, ‘b’, ‘c’, ‘d’].includes(‘b’, 2); // false
与 indexOf 方法对比,下面方法效果相同:
[‘a’, ‘b’, ‘c’, ‘d’].indexOf(‘b’) > -1; // true
[‘a’, ‘b’, ‘c’, ‘d’].includes(‘b’); // true
includes()与 indexOf 对比:

includes 相比 indexOf 更具语义化,includes 返回的是是否存在的具体结果,值为布尔值,而 indexOf 返回的是搜索值的下标。

includes 相比 indexOf 更准确,includes 认为两个 NaN 相等,而 indexOf 不会。

let a = [1, NaN, 3];
a.indexOf(NaN); // -1
a.includes(NaN); // true
另外在判断 + 0 与 - 0 时,includes 和 indexOf 的返回相同。
[1, +0, 3, 4].includes(-0); // true
[1, +0, 3, 4].indexOf(-0); // 1
参考资料
1.MDN 索引集合类 2.MDN 数组对象 3.W3school JavaScript Array 对象

本部分内容到这结束

Author
王平安

E-mail
pingan8787@qq.com

博 客
www.pingan8787.com

微 信
pingan8787

每日文章推荐
https://github.com/pingan8787…

ES 小册
es.pingan8787.com

正文完
 0