JavaScript——数组详解(超详细)
数组就是一组数据的集合,其表现形式就是内存中的一段连续的内存地址
数组名称其实就是连续内存地址的首地址
JavaScript数组特点
-
数组定义时无需指定数据类型
-
数组定义时可以无需指定数组长度
-
数组可以存储任何数据类型的数据
创建数组
1.使用Array
构造函数
let arr1=new Array()
let arr2=new Array(10) //给Array构造函数传一个数值,length会被自动创建并设置为这个值
let arr3=new Array("小米","华为","Apple") //给Array构造函数传入要保存的元素,arr3=["小米","华为","Apple"]
let arr4=new Array("hello")//给Array构造函数传一个特定值,创建一个只包含一个元素的数组,arr4[0]=hello
//使用Array构造函数时,可以省略new操作符
let arr5=Array(3) //创建一个包含三个元素的数组
let arr6=Array("hello") //创建一个只包含一个元素的数组,即arr6[0]=hello
2.使用数组字面量表示法
let colors=["red","green","blue"];
let arr=[] //创建空数组
let nums=[1,2,3] //创建一个包含三个元素的数组
(使用数组字面量表示法创建数组时,不会调用Array构造函数)
3. ES6新增创建数组的静态方法
Array.from()
将类数组结构转化为数组实例,第一个参数为一个类数组对象,即任何可迭代的结构,或者有一个length
属性和可索引元素的结构
- 将类数组转换为真正的数组
//将类数组转换为真正的数组
let arr={
0:'aaa',
1:'111',
2:['hhh','ccc','eee'],
"length":3
}
console.log(Array.from(arr))//['aaa','111',['hhh','ccc','eee']]
//没有length属性
let arr={
0:'aaa',
1:'111',
2:['hhh','ccc','eee'],
}
console.log(Array.from(arr))//[]
(没有length属性,会输出一个长度为0的空数组)
- 将字符串拆分为单字符数组(取代
join
)
console.log(Array.from("Hello")) // ['H','e','l','l','o']
set
转数组
const set=new Set([1,1,2,2,4,5,6])
console.log(Array.from(set)) //[1,2,4,5,6]
map
转数组
const mapper = new Map([['name', 'mike'], ['age', 11]]);
let Arr = Array.from(mapper.values());// 获取map的值数组
let Arr1 = Array.from(mapper.keys());// 获取map的值数组
console.log(Arr) //["mike",11]
console.log(Arr1) //["name",age]
- 函数
arguments
转数组
function test01() {
console.log(Array.from(arguments));
}
test01(1, 2, 3, 4) //[1,2,3,4]
- 接收第二个参数,代替
map
,对每个元素进行处理,处理之后放回返回的数组
let arr = [12,45,97,9797,564,134,12642]
let set = new Set(arr)
console.log(Array.from(set, item => item + 1)) // [ 13, 46, 98, 9798, 565, 135, 12643 ]
- 接收第三个参数,用于指定映射函数中this的值(重写的this值在箭头函数中不适用)
const a1=[1,2,3,4]
const a2=Array.from(a1,function(x){ return x**this.index},{index:2})
console.log(a2) //[1,4,9,16]
- 数组去重合并
function combine(){
let arr=[].concat.apply([],arguments);//没有去重复的新数组
return Array.from(new Set(arr))
}
var m=[1,2,2],n=[2,3,3];
console.log(combine(m,n)) //[1,2,3]
Array.of()
将一组参数转化为数组,主要目的是弥补数组构造函数Array()的不足
console.log(Array.of(1,2,3,4))//[1,2,3,4]
console.log(Array.of())//[]
console.log(Array.of(undefined))//[undefined]
数组空位
ES6
之前,将,之间相应的索引位置当成空位
let arr=[,,,,,];//创建包含5个元素的数组
console.log(arr.length) //5
console.log(arr) //[,,,,,]
具体行为应方法而定
let arr=[1,,,4]
//map()跳过空位置
console.log(arr.map(()=>6)) //[6,undefined,undefined,6]
//join()将空位置视为空字符串
console.log(arr.join('-')) //1---4
ES6
新增方法普遍将这些空位当成存在的元素,值为undefined
let arr=[1,,,,5]
for(let option of arr){
console.log(option===undefined)
}
//false true true true false
//...扩展运算符
console.log(Array.of(...[,,,]))//[undefined,undefined,undefined]
检测数组
instanceof
适用于只有一个网页(一个全局作用域)的情况下
if(value instanceof Array) {
//操作数组
}
Array.isArray()
if(Array.isArray(value) ) {
//操作数组
}
迭代器方法
- ES6中,Array的原型上暴露3个用于检测数组内容和方法
keys()
返回数字索引的迭代器values()
反复数组元素的迭代器entries()
返回索引/值对的迭代器
let a=['aaa','bbb','ccc']
const aKeys=Array.from(a.keys())
const aValues=Array.from(a.values())
const aEntries=Array.from(a.entries())
console.log(aKeys) //[0,1,2]
console.log(aValues)//['aaa','bbb','ccc']
console.log(aEntries)//[[0, 'aaa'],[1, 'bbb'],[2, 'ccc']]
- ES6解构赋值,可以容易在循环中拆分键值对
let a=['aaa','bbb','ccc']
for(let [index,id] of a.entries()) {
console.log(index)
console.log(id)
}
//0
//aaa
//1
//bbb
//2
//ccc
数组的填充和复制方法
ES6新增两个方法,批量复制方法fill()
以及填充数组方法copyWithin()
fill()
批量复制方法:可以向一个已有数组中插入全部和部分相同的值,这个方法有三个参数,从左到右依次为要填充的数据,填充的起始位置(默认为0),停止填充的位置(默认是数组的长度)
,这个方法不改变原数组
let arr = [0,0,0,0,0]
let res = arr.fill(1,1,2)//用1填充索引大于等于1且小于2的元素
console.log(res) // [0, 1, 0, 0, 0]
let oneParam = arr.fill(1)
console.log(oneParam) // [1,1,1,1,1]
console.log(arr) // [0,0,0,0,0] 不改变原数组
let arr1=[0,0,0,0,0]
console.log(arr1.fill(1,-10,-6))// [0,0,0,0,0] 索引过低,忽略
console.log(arr1.fill(1,10,15)) // [0,0,0,0,0] 索引过高,忽略
console.log(arr1.fill(1,-4,2)) // [0,0,0,0,0] 索引反向,忽略
console.log(arr1.fill(1,3,10)) // [0,0,0,1,1] 索引部分可用
copyWithin()
填充数组方法.在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组(但不会修改数组长度).arr.copyWithin(target,start,end)
接受三个参数:- target (必需):从该位置开始替换数据。
- start (可选):从该位置开始读取数据,默认为 0 ,如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
这三个参数都应该是数值,如果不是,会自动转为数值。
let ints, reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
reset();//重置ints数组
// 从ints中复制索引0开始的内容,插入到索引5开始的位置
ints.copyWithin(5)
console.log(ints) //[0,1,2,3,4,0,1,2,3,4]
// 从ints中复制索引5开始的内容,插入到索引0开始的位置
reset();
ints.copyWithin(0, 5)
console.log(ints) //[ 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]
// 从ints中复制索引0开始,3结束的内容,插入到索引4开始的位置
reset();
ints.copyWithin(4,0,3)
console.log(ints)//[0,1,2,3,0,1,2,7,8,9]
// 支持负值索引 从右往左,复制索引为7到索引为3,插入索引为4开始的位置
reset();
ints.copyWithin(-4,-7,-3)
console.log(ints) //[0,1,2,3,4,5,3,4,5,6]
copyWithin()
静默忽略超出数组边界,零长度及方向相反的索引范围
let ints, reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
reset();
ints.copyWithin(1,-15,-12) //索引过低,忽略
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset();
ints.copyWithin(1,-12,15) //索引过高,忽略
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset();
ints.copyWithin(2,4,2) //索引反向,忽略
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset();
ints.copyWithin(4,7,10) //索引部分可用,填充部分可用
console.log(ints) // [0, 1, 2, 3, 7, 8, 9, 7, 8, 9]
数组转换方法
所有对象都有toLocaleString()
toString()
valueOf()
方法.
-
valueOf()
返回数组本身let a = [1,2,3,4,5,6,7,8,9,0] let s = a.valueOf() console.log(s); //[1,2,3,4,5,6,7,8,9,0]
-
toString()
返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串
let a = [1,2,3,4,5,6,7,8,9,0]
let s = a.toString()
console.log(s); //"1,2,3,4,5,6,7,8,9,0"
//alert方法需要接收字符串参数,所以会在后台调用toString()方法
alert(a)//"1,2,3,4,5,6,7,8,9,0"
-
toLocaleString()
toLocaleString()
经常与toString()
方法返回的值相同,但有的时候不同。当数组调用toLocaleString()
方法时,调用的是每一项的toLocaleString()
,而不是toString()
let person1 = { toString: function(){ return 'pp'; }, toLocaleString:function(){ return 'oo'; } } let person2 = { toString: function(){ return 'op'; }, toLocaleString:function(){ return 'po'; } } alert([person1,person2]); //pp,op alert([person1,person2].toString()); //pp,op alert([person1,person2].toLocaleString()); //oo,po let person1 = { toString: function(){ return 'pp'; }, toLocaleString:function(){ return 'oo'; } } let person2 = { toString: function(){ return 'op'; }, toLocaleString:function(){ return 'po'; } } alert([person1,person2]); //pp,op alert([person1,person2].toString()); //pp,op alert([person1,person2].toLocaleString()); //oo,po
-
join()
接收一个参数,即字符串分隔符,返回包含所有项的字符串var arr = ['gao','wanlimm','ssmay'] console.log(arr.join('-'))//gao-wanlimm-ssmay
数组的栈方法 队列方法
- 数组中栈方法
push()
、pop()
- 栈是一种*LIFO(Last-In-First-Out,后进先出)*的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入,push)和移除(叫做弹出,pop),只发生在一个位置,即栈的顶部。ECMAScript为数组专门提供了push()和pop()的方法,以便实现类似栈的行为。
push()
方法可以接收任意数量的参数,把他们逐个添加到数组的末尾,并返回修改后数组的长度。而pop()
方法则从数组末尾移除最后一项,数组的lenrth值减1,然后返回移除的项.
- 栈是一种*LIFO(Last-In-First-Out,后进先出)*的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入,push)和移除(叫做弹出,pop),只发生在一个位置,即栈的顶部。ECMAScript为数组专门提供了push()和pop()的方法,以便实现类似栈的行为。
let colors = ["red","green","pink"];
let count = colors.push("orange","yellow");
console.log(count); // ["red","green","pink","orange","yellow"]
var item = colors.pop();
console.log(colors.length); //数组长度为3
console.log(item); //“yellow"
-
数组中的队列方法
shift()
unshift()
-
队列数据结构的访问规则是FIFO(First-In-First-Out,先进先出)。队列在列表的末端添加项,从列表的前端移除项。由于
push()
是向数组末端添加项的方法,因此模拟队列只需一个从数组前端取得项的方法。实现这一操作的方法就是shift()
,它能够移除数组中的第一项并返回该项,同时将数组的长度减1。结合使用shift()
和push()
方法,可以像用队列一样使用数组。let colors = ["red","green","pink"]; let item = colors.shift(); console.log(colors.length);//返回数组长度2 console.log(item); //“red"
-
unshift()
在数组的前端添加任意个项并返回新数组的长度var colors = ["red","green","pink"]; var item = colors.unshift("orange"); console.log(colors.length); //返回数组长度4 console.log(item); //4
-
排序方法
-
reverse()
将数组元素反向排列let arr=[1,2,3,4,5] arr.reverse() console.log(arr)//5,4,3,2,1
-
sort()
默认按照升序重新排列数组元素,sort()
在每一项上调用String()转型函数,然后比较字符串来决定顺序。即使数组元素都是数值,也会转化为字符串再比较,排序let arr=[2,1,3,0,4] arr.sort() console.log(arr)//0,1,2,3,4 arr=[1,10,5,6] arr.sort() console.log(arr)//1,10,5,6
-
sort()
接收一个比较函数,用于判断哪个值应该排在前面function compare(val1, val2) { if (val1 < val2) { return -1 } else if (val1 > val2) { return 1 } else { return 0 } } let arr = [1, 10, 15, 8] arr.sort(compare) console.log(arr)//[1,8,10,15]
-
sort()
实现降序效果function compare1(val1, val2) { if (val1 < val2) { return 1 } else if (val1 > val2) { return -1 } else { return 0 } } let arr1 = [1, 10, 15, 8] arr.sort(compare1) console.log(arr)//[15,10,8,1]
注意:
reverse()
和sort()
都返回调用他们数组的引用 -
数组的操作方法
-
三个严格相等的搜索方法
indexOf()
lastIndexOf()
includes()
,includes()
为ES7新增-
这三个方法都接收两个参数:要查找的元素和一个可选的起始搜索位置
-
indexof()和includes()从前往后搜索
-
indexOf()
lastIndexOf()
返回索引值 -
lastIndexOf()从数组最后一项开始搜索,某个指定字符串在字符串中最后一次出现的位置(索引值)
-
includes()返回boolean值,在和每一个参数比较时,使用全等(===)
let arr = [1, 2, 4, 4, 5, 3, 3, 7, 8, 5] console.log(arr.indexOf(4)); // 2 第一次出现的索引值 console.log(arr.lastIndexOf(4)); // 3 console.log(arr.includes(4)); // true console.log(arr.includes(9)); // false
-
-
find()
findIndex()
从数组的最小索引开始,查找数组中符合条件的元素 -
通过
find()
方法来查找满足条件的对象
// 定义一个数组,里面包含多个对象,通过find方法来查找满足条件的对象
var arr = [
{
id: 1,
name:'张三'
},
{
id: 2,
name:'张三'
}
]
// find方法返回一个函数,函数可传递两个形参 item index
// 也就是说可通过item 项判断满足参数来查找元素也可以通过 index 索引来查找元素
var item = arr.find(item => item.id == 1 )
console.log(item) // 输出id = 1 的对象
findIndex()
找到元素则输出第一个符合条件元素的位置(索引的值从0开始),如果没有找到则返回 -1
var arr1 = [10,20,30,50,40]
var index = arr1.findIndex((value, index) => value > 5 )
console.log(index) //0 (10>5)
const arr = [
{name:'老大',age:10},
{name:'老二',age:9},
{name:'老三',age:8}
];
const a = arr.find(({ name }) => name === '老二');
const b = arr.findIndex(({ name }) => name === '老二');
console.log(a);//{name:'老二';age:9};
console.log(b);//1
迭代方法
forEach()
对数组中的每一项执行函数,没有返回值。类似于for循环
var arr=[1,1,3,4,5,6];
arr.forEach((item,index,array)=>{
item+=1;
console.log(item);//2,2,4,5,6,7
});
console.log(arr);//[1,1,3,4,5,6]
every()
迭代数组每一项,每项都符合条件的才返回true,反之false
var arr=[1,1,3,4,5,6];
var result=arr.every((item,index,array)=>{
return (item>2);
});
console.log(result);//false
some()
对数组中的每一项执行函数,只要有一项返回了 true ,则该方法返回 true
var arr=[1,1,3,4,5,6];
var result=arr.some((item,index,array)=>{
return (item>2);
});
console.log(result);//true
filter()
对数组中的每一项执行函数,把里面返回 true 的项,组成一个数组返回
var arr=[1,1,3,4,5,6];
var result=arr.filter((item,index,array)=>{
return (item>2);
});
console.log(result);//[3,4,5,6]
map()
对数组中的每一项执行函数,返回(处理后的)每一项
var arr=[1,1,3,4,5,6];
var result=arr.map((item,index,array)=>{
return (item*2);
});
console.log(result);//[2,2,6,8,10,12]
归并方法
reduce()
与 reduceRight()
这两个方法都会迭代数组的所有项,并在此基础上构建一个最终的返回值reduce()
方法从数组第一项开始遍历到最后一项reduceRight()
方法从最后一项遍历到第一项使用reduce()
还是reduceRight()
,主要取决于要从哪头开始遍历数组。除此之外,它们完全相同。
-
接收两个参数
- 对每一项都会运行的归并函数 .
- 可选的归并起点的初始值
-
归并函数接收四个参数
- 上一个归并值
- 当前项
- 当前项的索引
- 数组本身
数组累加
//一般方法 let values = [1, 2, 3, 4, 5]; let sum = 0; values.forEach((item)=>{ sum += item; }) console.log(sum); // 15
//reduce()方法 let values = [1, 2, 3, 4, 5]; let sum = values.reduce((prev, cur, index, array) => prev + cur); console.log(sum); // 15 /*执行过程 1+2=3 3+3=6 6+4=10 10+5=15*/
数组累乘
function Multiplication(...vals) { return vals.reduce((prev, cur) => prev * cur, 1); } Multiplication(1, 2, 3, 4, 5); // 120