除了Object,Array应该就是ECMAScript中最常用的类型了。
ECMAScript 数组与其他语言相同,是一组有序数据,不同的是数组的每个槽位可以存储任意类型的数据。ECMAScript 数组是动态大小的,会随着数据添加而自动增长。


文章目录

  • 1. 创建数组
  • from()
  • of()
  • 2. 数组空位
  • 3. 数组索引
  • 4. 检测数组
  • 5. 迭代器方法
  • keys()
  • values()
  • entries()
  • 6. 复制和填充方法
  • fill()
  • copyWithin()
  • 7. 转换方法
  • toSring()
  • valueOf()
  • toLocaleString()
  • join()
  • 8. 栈方法与队列方法
  • push()
  • pop()
  • shift()
  • unshift()
  • 9. 排序方法
  • reverse()
  • sort()
  • 10. 操作方法
  • concat()
  • slice()
  • splice()
  • 11. 搜索和位置方法
  • 1)严格相等 (indexOf、lastIndexOf、includes)
  • 2)断言函数(find、findIndex)
  • 12. 迭代方法
  • every()
  • filter()
  • forEach()
  • map()
  • some()
  • 13. 归并方法 (reduce、reduceRight)


1. 创建数组


// 1. 使用Array构造函数
let colors = new Array(20);		// 创建初始length为20的数组
let colors = new Array("grey");	// 创建包含字符串"grey"的数组
let colors = Array(3);			// 省略new操作符,构造结果相同

// 2. 使用数组字面量
let colors = ["grey", "red", "blue"];	// 创建一个包含3个元素的数组
let colors = [];						// 创建一个空数组

ES6新增的用于创建数组的静态方法 form(),of()

from()

参数:①一个类数组对象(任何可迭代结构),②映射函数(数组中每个元素要调用的函数,可选),③指定映射函数中this的值(此值在箭头函数中不适用)
返回:一个新的数组实例

const a = Array.from("case");
console.log(a);		// ["c","a","s","e"]

const a1 = [1,2,3,4];
const a2 = Array.from(a1, x=>x**2);
const a3 = Array.from(a1, function(x){return x**this.ex}, {ex:2});	// 使用第三个参数的值,第二个参数不能用箭头函数
console.log(a2);	// [1, 4, 9, 16]
console.log(a3);	// [1, 4, 9, 16]

of()

参数:任意个参数,将按顺序成为返回数组中的元素。
返回:一个新的数组实例

console.log(Array.of(1,2,3,4));		// [1, 2, 3, 4]

// 与Array的区别
const a1 = Array(7);		// [ , , , , , , ]
const a2 = Array.of(7);		// [7]




2. 数组空位


使用数组字面值初始化数组时,可以使用一串逗号来创建空位。 ES6新增方法普遍将这些空位当成存在的元素,只不过值为undefined。

const nums = [1, , , , 5];
for(const num of nums){
	console.log(num === undefined);		// false true true true false
}

注意:实践中要避免使用数组空位,如果确实需要,则可以显式地用undefined值代替。




3. 数组索引


取得或设置数组的值,使用中括号提供索引。

数组中元素数量的值保存在length中。length不是只读的,通过修改length,可以从数组末尾删除或添加元素。

let colors = ["grey", "red", "blue"];
colors.length = 2;		// 删除了最后一个值
console.log(colors[2]);	// undefined

colors[99] = "red";		// length = 100, 中间位置的元素未赋值,全为undefined
console.log(colors[80]);	// undefined

注意:数组中最多可以包含 4 294 967 295 个元素。




4. 检测数组


在只有一个网页(因而只有一个全局作用域)的情况下,使用 instanceof 足矣。

if(value instanceof Array){ ... }

如果网页中有多个框架,则可能涉及两个不同的全局执行上下文,因此会有两个不同版本的Array构造函数。ECMAScript 提供了 Array.isArray()方法。这个方法的目的就是确定一个值是否为数组,而不管它是在哪个全局执行上下文中创建的。
if(Array.isArray(value)){ ... }




5. 迭代器方法


三个方法都返回迭代器对象

keys()

返回数组索引的迭代器

values()

返回数组元素的迭代器

entries()

返回索引 / 值对的迭代器

const a = ["jack","cathy","tom","ming"];
// 通过Array.from()直接转换为数组实例
const aK = Array.from( a.keys() );		// [0, 1, 2, 3]
const aV = Array.from( a.values() );	// ["jack","cathy","tom","ming"]
const aE = Array.from( a.entries() );	// [[0,"jack"],[1,"cathy"],[2,"tom"],[3,"ming"]]

使用ES6的解构可以非常容易地在循环中拆分键值对

const a = ["jack","cathy","tom","ming"];
for(const [id, element] of a.entries()){
	console.log(id);
	console.log(element);
}
// 0
// jack
// 1
// cathy
// 2
// tom
// 3
// ming




6. 复制和填充方法


fill()

向一个数组中插入全部或部分相同的值
参数:①填充值,②开始索引(可选),③结束索引(可选)

const zeroes = [0, 0, 0, 0, 0];
zeroes.fill(5);				// [5, 5, 5, 5, 5]
zeroes.fill(6, 3);			// [0, 0, 0, 6, 6]	从索引为3开始填充直到数组末尾
zeroes.fill(7, 1, 3);		// [0, 7, 7, 0, 0]	填充索引大于等于1小于3的元素
zeroes.fill(8, -4, -1);		// [0, 8, 8, 8, 0]	填充索引大于等于1小于4的元素

// fill()会忽略超出数组边界、零长度及方向相反的索引范围
zeroes.fill(1, 10, 15);		// [0, 0, 0, 0, 0]	超出数组边界
zeroes.fill(1, 4, 2);		// [0, 0, 0, 0, 0]	索引反向
zeroes.fill(1, 3, 10);		// [0, 0, 0, 1, 1]	填充可用部分

copyWithin()

按照指定范围浅复制数组中的部分内容
参数:①插入开始索引,②复制开始索引(可选),③复制结束索引(可选)

const ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
ints.copyWithin(5);			// [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] 无复制开始索引则从0开始复制
ints.copyWithin(0, 5);		// [5, 6, 7, 8, 9, 5, 6, 7, 8, 9] 无复制结束索引复制到数组结尾结束
ints.copyWithin(2, 0, 6);	// [0, 1, 0, 1, 2, 3, 4, 5, 8, 9]

// copyWithin()会忽略超出数组边界、零长度及方向相反的索引范围
ints.copyWithin(1, 12, 15);	// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 超出数组边界
ints.copyWithin(1, 5, 2);	// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 索引反向
ints.copyWithin(1, 7, 15);	// [0, 7, 8, 9, 4, 5, 6, 7, 8, 9] 填充可用部分




7. 转换方法


所有的对象都有toLocaleString()、toString()、valueOf()方法

toSring()

toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分割的字符串
即对数组的每个值调用其toString()方法,以得到最终字符串。

let people = ["jack","cathy","tom"];
console.log(people.toString());		// jack,cathy,tom

valueOf()

返回的还是数组本身。

let people = ["jack","cathy","tom"];
console.log(people.valueOf());		// ["jack", "cathy", "tom"]

toLocaleString()

调用数组每个值的toLocaleString()方法

let people = ["jack","cathy","tom"];
console.log(people.toLocaleString());		// jack,cathy,tom

join()

想使用不同的分隔符使用join()方法

let people = ["jack","cathy","tom"];
console.log(people.join());			// jack,cathy,tom  不传参数默认用","分隔
console.log(people.join("@@"))		// jack@@cathy@@tom




8. 栈方法与队列方法


栈:先进后出
队列:先进先出

push()

参数:接收任意数量参数,将它们添加到数组末尾
返回:数组最新长度

let colors = ["grey", "red", "blue"];
let len = colors.push("yellow","green");	// len = 5
							// ["grey", "red", "blue", "yellow", "green"]

pop()

参数:无参数,删除数组最后一项
返回:被删除的项

let colors = ["grey", "red", "blue"];
let item = colors.pop();	// item = "blue"
alert(colors.length);		// 2

shift()

参数:无参数,删除数组第一项
返回:被删除的项

let colors = ["grey", "red", "blue"];
let item = colors.shift();	// item = "grey"
alert(colors.length);		// 2

unshift()

unshift()就是执行与shift()相反的操作
参数:接收任意数量参数,将它们添加到数组开头
返回:数组最新长度

let colors = ["grey", "red", "blue"];
let len = colors.unshift("black","white");	// len = 5
							// ["black", "white", "grey", "red", "blue"]




9. 排序方法


reverse()

将数组元素反向排序

let values = [4, 2, 5, 1, 3];
values.reverse();
console.log(values);	// [3, 1, 5, 2, 4]

sort()

默认按照升序排列数组,sort()会在每一项上调用String()转型函数,然后比较字符串来决定顺序。

let values1 = [3, 2, 7, 6, 9];
values1.sort();		// [2, 3, 6, 7, 9]

// 由于是比较字符串决定顺序,就会出现下面的情况
let values2 = [0, 1, 5, 10, 15];
values2.sort();		// [0, 1, 10, 15, 5]

参数:sort()函数可以接收一个比较函数

比较函数接收两个参数,第一个参数应该排在第二个参数前面,就返回负值;两个参数相等,返回0;第一个参数应该排在第二个参数后面,就返回正值

// 一个简单的比较函数,适用于大多数数据类型
function compare(value1, value2){
	if(value1 < value2){
		return -1;
	} else if(value1 > value2){
		return 1;
	} else {
		return 0;
	}
}

let values = [0, 1, 5, 15, 10];
values.sort(compare);
console.log(values);		// [0, 1, 5, 10, 15]

// 可简写为一个箭头函数
let values = [0, 1, 5, 15, 10];
values.sort( (a,b) => a<b ? -1 : (a>b?1:0) );
console.log(values);	 	// [0, 1, 5, 10, 15]

如果只是比较数值,比较函数可以写的很简单---->直接做减法。
比较函数就是要返回小于0,0和大于0的数值,减法操作可以完全满足要求。

let values = [0, 1, 5, 15, 10];
values.sort( (a,b)=>a-b );
console.log(values);		// [0, 1, 5, 10, 15]
values.sort( (a,b)=>b-a );
console.log(values);		// [15, 10, 5, 1, 0]

注意:reverse()和sort()都返回调用它们数组的引用。




10. 操作方法


concat()

可以在现有数组全部元素基础上创建一个新数组。
该方法首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组。

参数:接收任意数量参数(如果参数是数组,则会把数组的每一项都添加到结果数组,如果不是数组,则直接添加到数组末尾)
返回:新构建的数组

let colors = ["grey", "red", "blue"];
let colors2 = colors.concat("yellow", ["black", "white"]);
console.log(colors2);	// ["grey", "red", "blue", "yellow", "black", "white"]

//参数数组上指定一个特殊符号可以阻止concat()打平参数数组 【Symbol.isConcatSpreadable】
let colors = ["grey", "red", "blue"];
let newColors = ["black", "white"];
newColors[Symbol.isConcatSpreadable] = false;
let colors2 = colors.concat("yellow", newColors);
console.log(colors2);	
			// ["grey", "red", "blue", "yellow", ["black", "white"]]

slice()

参数:①返回元素开始索引,②结束索引
返回:一个新数组

let colors = ["res", "green", "blue", "yellow", "purple"];
let colors2 = colors.slice(1);		// ["green", "blue", "yellow", "purple"] 无结束索引,复制到数组末尾
let colors3 = colors.slice(1, 4);	// ["green", "blue", "yellow"] 从索引1复制到3

splice()

splice()的主要目的是在数组中间插入元素,有3种不同的方式使用这个方法。

  • 删除
    参数:①删除的第一个元素的位置,②删除的数量
  • 插入
    参数:①开始位置,②0(删除数量),③要插入元素(可传多个参数作为插入元素)
  • 替换
    参数:① 开始位置,②要删除数量,③要插入的任意多个元素

返回:被删除的元素数组

let colors = ["grey", "red", "blue"];
// 删除两项
let removed = colors.splice(0,2);
console.log(colors);		// ["blue"]
console.log(removed);		// ["grey", "red"]
// 插入	["blue"]
colors.splice(1, 0, "red", "yellow");
console.log(colors);		// ["blue", "red", "yellow"]
// 替换 ["blue", "red", "yellow"]
colors.splice(2, 1, "black")
console.log(colors);		// ["blue", "red", "black"]




11. 搜索和位置方法


提供两类搜索数组的方法:按严格相等搜索 和 按断言函数搜索

1)严格相等 (indexOf、lastIndexOf、includes)

参数:①要查找的元素,②起始搜索位置(可选)
返回:indexOf()和lastIndexOf()都返回查找元素所在的位置、没找到返回-1,includea()返回布尔值

在比较时使用 === 比较,即严格相等
indexOf()、includes()从数组第一项开始搜索,lastIndexOf()从数组末尾开始向前搜索。

let nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];
alert(nums.indexOf(4,2));		// 3
alert(nums.indexOf(4,7));		// -1
alert(nums.lastIndexOf(4,7));	// 5
alert(nums.lastIndexOf(4,2));	// -1
alert(nums.includes(4,2));		// true

2)断言函数(find、findIndex)

参数:①一个断言函数,②指定断言函数内部的this值(可选)
返回:find()返回第一个匹配的元素,findIndex()返回匹配的索引

两个方法都从数组的最小索引开始搜索。找到匹配项后,这两个方法都不再继续搜索。

断言函数的参数
参数:①元素、②索引、③数组本身

const people = [
	{
		name: "Mike",
		age: 24
	},
	{
		name: "Cathy",
		age: 27
	}
]

people.find( (element, index, array) => element.age < 25 );			// {name:"Mike", age:24}
people.findIndex( (element, index, array) => element.age < 25 );	// 0




12. 迭代方法


每个方法都接收两个参数
参数:①以每一项为参数运行的函数,②作为函数运行时上下文的作用域对象(可选)
函数参数:①数组元素、②元素索引、③数组本身

every()

返回:如果对每一项函数都返回true,则返回true

filter()

返回:函数返回true的项组成数组后返回

forEach()

返回:没有返回值

map()

返回:由每次函数调用的结果构成的数组

some()

返回:如果对有一项函数返回true,则返回true

注意:这些方法都不改变调用它们的数组

every()与some()

let nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];
alert( nums.every( (item,index,array)=>item>2 ) );	// flase
alert( nums.some( (item,index,array)=>item>2 ) );	// true

filter()

// 返回一个所有数值都大于2的数组
let nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let filterResult = nums.filter( (item,index,array)=>item>2 );
console.log(filterResult);		// [3, 4, 5, 4, 3]

map()

// 返回原数组每项×2的数组
let nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let mapResult = nums.map( (item,index,array)=>item*2 );
console.log(mapResult);		// [2, 4, 6, 8, 10, 8, 6, 4, 2]

forEach()

// forEach()方法相当于for循环遍历数组
let nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];
nums.forEach( (item,index,array) => {
	// 执行某些操作
})




13. 归并方法 (reduce、reduceRight)


两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。
参数:①函数,②作为起点的初始值(可选)
函数参数:①上一个归并值,②当前项,③当前项的索引,④数组本身

reduce()方法从数组第一项开始遍历到最后一项,reduceRight()从最后一项遍历到最后一项。

如果没有给方法传第二个参数作为起点,则第一次迭代从数组的第二项开始,即传给归并函数的第一个参数是数组的第一项,第二个参数是数组的第二项。

let values = [1, 2, 3, 4, 5];
let sum = values.reduce( (prev, cur, index, array)=>prev+cur );
console.log(sum);		// 15

究竟是使用reduce()还是reduceRight(),只取决于遍历数组元素的方向,除此之外,这两个方法没区别。