【重温基础】10.数组

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

系列目录:git

本章节复习的是JS中的数组,以索引进行排序。 github

前置知识:
数组是一个有序的数据集合,使用数组名称和索引进行访问。正则表达式

let arr = [1,2,3];
arr[0] = 1;

在JavaScript中数组没有明确数据类型。segmentfault

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;

若传入的数组长度不是整数,则报错:app

let arr = new Array(3.5); 
let arr = Array(3.5); 
let arr = [];
arr.length = 3.5;
//Uncaught RangeError: Invalid array length

其中要注意这两种建立方法是不一样的:ide

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

对数组的元素进行排序,改变原数组
可接受一个回调方法做为比较函数,来决定排序方式。
比较函数应该具备两个参数 ab,返回值以下:
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时,includesindexOf的返回相同。

[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...
JS小册 js.pingan8787.com

欢迎关注微信公众号【前端自习课】天天早晨,与您一块儿学习一篇优秀的前端技术博文 .

相关文章
相关标签/搜索