Array
JavaScript中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性。
JavaScript中的数组严格意义上是对象,被当做对象,在内部被归结为数组。
一、创建数组
(1)字面量表示
直接通过 [ ] 操作符声明一个数组变量
var arr = [];
var arr2 = [1,2,3,4];
(2)构造函数方式
通过new一个构造函数来创建
var arr = new Array(1,2,3,4)
(3)Array.of 创建数组
从给定参数创建数组
var arr = Array.of(3);
var arr2 = Array.of(1,2,3);
(4)Array.from 创建数组
用类数组或可迭代对象创建新数组。
var arr = Array.from('abcd');
var arr2 = Array.from([1, 2, 3], x => x + 1);
二、判断数组
Array.isArray()
var arr = [1,3,4,5];
Array.isArray(arr);
// true
instanceof Array
var arr = [1,3,4,5];
arr instanceof Array;
// true
三、数组的属性
属性 | 描述 |
---|---|
constructor | 返回对创建此对象的数组函数的引用。 |
length | 设置或返回数组中元素的数目。 |
prototype | 使您有能力向对象添加属性和方法。 |
四、数组的方法
修改原有数组 | 生成新的数组 |
---|---|
push() 尾部添加 | filter() 过滤函数 |
pop() 尾部删除 | concat() 合并 |
shift() 头部删除 | slice() 截取 |
unshift() 头部添加 | map() 遍历映射 |
splice() 添加替换删除 | reduce() 累计器 |
sort() 排序 | |
reverse() 倒序 | |
copyWithin() 内部复制 |
🎵注意:
修改原数组的这些方法,还需要注意一点,就是数组本身会改变,这些方法的返回值也可以利用
方法 | 描述 | 返回 |
---|---|---|
push | 向数组的末尾添加一个或多个元素 | 添加后的新长度 |
pop | 删除数组的最后一个元素(无参) | 删除的元素的值,空则返回 undefined |
unshift | 向数组的开头添加一个或更多元素 | 添加后的新长度 |
shift | 删除数组第一个元素(无参) | 删除的元素的值,空则返回 undefined |
splice | 向/从数组中添加/删除项目 | 被删除的项目 |
循环方法 |
---|
forEach() map() filter() some() every() |
①添加元素
push()
将一个元素添加到数组末尾
var arr = [1,2,3];
console.log(arr); //(3) [1, 2, 3]
arr.push(4);
console.log(arr); //(4) [1, 2, 3, 4]
arr.push(undefined);
console.log(arr); //(5) [1, 2, 3, 4, undefined]
添加各种数据类型都是可以的
可以添加一个或者多个元素
是直接修改原数组
unshift()
将元素添加在数组的开头
var arr = [1,2,3,4];
console.log(arr); //(4) [1, 2, 3, 4]
arr.unshift(0);
console.log(arr); //(5) [0, 1, 2, 3, 4]
arr.unshift(-2,-1);
console.log(arr); //(7) [-2, -1, 0, 1, 2, 3, 4]
可以添加一个或者多个元素
是直接修改原数组
②删除元素
pop()
删除并返回数组的最后一个元素,把数组长度减 1,并且返回它删除的元素的值。
如果数组已经为空,则 pop() 不改变数组,并返回 undefined 值。
var arr = [1,2,3,4,5];
arr.pop();
console.log(arr); //(4) [1, 2, 3, 4]
var arr2 = [2];
arr2.pop();
console.log(arr2); //[]
改变了数组的长度,修改原数组。
shift()
把数组的第一个元素从其中删除,并返回第一个元素的值。
var arr = [1,2,3,4,5];
arr.shift();
console.log(arr); //(4) [2, 3, 4, 5]
改变了数组的长度,修改原数组。
③重要的splice()
向/从数组中添加/删除项目,然后返回被删除的项目。数组被修改。
语法
arrayObject.splice(index,howmany,item1,.....,itemX)
参数
- index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
- howmany:必需。要删除的项目数量。如果设置为 0,则不会删除项目。
- item…:可选。向数组添加的新项目。
返回
- Array 包含被删除项目的新数组(如果有的话)
这个函数功能比较复杂,拆分一下来看
1) 向某个位置添加元素
确定好索引位置,howmany设置为0,插入新的元素。
var arr = ['a', 'b', 'c', 'd'];
arr.splice(1,0,'a1');
console.log(arr); //(5) ["a", "a1", "b", "c", "d"]
即,我们在1的位置插入新元素"a1",也就是在当前索引的前面挤进去。
2) 删除某个位置的元素
确定好索引位置和要删除的个数,不添加第三个参数item就可以
var arr = ['a', 'b', 'c', 'd'];
arr.splice(2,2);
console.log(arr); //(2) ["a", "b"]
即,在2号位置删除2个元素
3) 替换某个位置的元素
替换也就是删除 + 添加,在指定索引位置删除元素,再添加新的item进去
var arr = ['a', 'b', 'c', 'd'];
arr.splice(0,1,'A');
console.log(arr); //(4) ["A", "b", "c", "d"]
即,删除0号位置的一个元素,添加“A”进去,完成替换。
总结:会改变原始数组
④合并数组
concat()
连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
arrayObject.concat(arrayX,arrayX,......,arrayX)
arrayX 必需,可以是具体的值,也可以是数组对象,可以是任意多个。
var arr1 = [1,2,3];
var arr2 = ['1', '2', '3'];
var newArr = arr1.concat(arr2);
console.log(newArr); //(6) [1, 2, 3, "1", "2", "3"]
返回的是一个新数组
⑤裁剪数组
slice()
从已有的数组中返回选定的元素。
返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。
即数组切片
语法
arrayObject.slice(start,end)
参数
start:必写。规定从何处开始选取。如果是负数就是倒数。
end:可选。规定从何处结束选取。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素,负数则倒数
var arr = ['a', 'b', 'c', 'd', 'e'];
newArr = arr.slice(2);
console.log(newArr); //(3) ["c", "d", "e"]
newArr2 = arr.slice(1,3);
console.log(newArr2); //(2) ["b", "c"]
按照索引值来,左闭右开,切片,跟python一样
不会修改数组,返回的是新数组
⑥查找数组元素
indexOf()
用来查找元素在数组中是否存在。如果存在,返回元素在数组中的索引;如果不存在,返回 -1。
如果数组中包含多个相同元素,该方法总是返回查找到的第一个。
var arr = [1,3,5,7,9];
i = arr.indexOf(1);
console.log(i); //0
j = arr.indexOf(4);
console.log(j); //-1
0表示索引位置,1表示不存在
var arr = [1,2,3,3,3,3,4,5];
index = arr.indexOf(3);
console.log(index); //2
有多个3,返回第一个3的位置
lastIndexOf()
返回最后一个找到的元素的索引,如果没有找到,就返回-1
includes()
值包含检测,如包含返回 true,不包含返回false。
var array1 = [1, 2, 3];
console.log(array1.includes(2)); // 输出 true
console.log(array1.includes(4)); // 输出 false
some()
some也可以,检测数组中是否有元素可以通过检测函数验证。
放在遍历那里展开
⑦数组转为字符串
join()
把数组中的所有元素放入一个字符串。
需要分隔符来把每一个元素分开,括号里传入的就是分隔符
var arr = ['a', 'b', 'c'];
newArr = arr.join();
console.log(newArr); //a,b,c
newArr2 = arr.join("-");
console.log(newArr2); //a-b-c
带逗号是console.log的一个特性
toString()
把数组转换为字符串,并返回结果。
返回值与没有参数的 join() 方法返回的字符串相同。
实际上,直接对一个数组使用
print()
函数时,系统会自动调用数组的toString()
方法。
⑧数组排序
reverse()
颠倒数组中元素的顺序。
修改原数组
var arr = [1,2,3,4,5,6,7];
arr.reverse();
console.log(arr); //(7) [7, 6, 5, 4, 3, 2, 1]
sort()
1)元素是字符串类型的按字母排序
var names = ['Dell', 'Bruce', 'Ford', 'Evan', 'Adam', 'Carl'];
names.sort();
console.log(names); //(6) ["Adam", "Bruce", "Carl", "Dell", "Evan", "Ford"]
按照A-Z的顺序排的
2)元素是数字类型的按大小排序
var arr = [2,4,1,5,7,8,6,3];
arr.sort((a,b) => a-b);
console.log(arr); //(8) [1, 2, 3, 4, 5, 6, 7, 8]
用箭头函数写了一个比较大小的匿名函数放在sort里面,其中 a-b 表示从小到大排列,b-a 表示从大到小排列。
arr.sort((a,b) => b-a);
console.log(arr); //(8) [8, 7, 6, 5, 4, 3, 2, 1]
⑨遍历数组
有5种数组迭代遍历方法,分别是
方法 | 说明 |
---|---|
every() | 遍历每一项,如果每一项都符合条件,就返回true |
some() | 遍历每一项,有一项满足,就返回true |
filter() | 过滤器,返回符合条件元素的新数组 |
forEach() | 仅遍历每一项,没有返回 |
map() | 遍历元素进行操作,返回操作后的新数组 |
这些方法都接受函数作为参数,其中函数的三个属性分别是(数组元素item
,元素索引index
,数组本身array
)
forEach() 遍历每一个
array.forEach(function(item,index,array){})
//一般使用箭头函数
array.forEach((item,index,array) => {});
后面接回调函数,回调函数里面填写三个参数
item
:数组当前项的值index
:数组当前项的索引array
:数组对象本身
这个函数没有返回值,就是相当于用for循环一遍
let arr = [1,2,3];
arr.forEach(function(value, index, array){
console.log(value); // 每个数组元素
console.log(index); // 每个元素的索引号
console.log(array); // 数组本身
})
let arr = [1,2,3,4,5,6];
let sum = 0;
arr.forEach(function(value, index, array){
sum += value;
});
console.log(sum); //数组求和
filter() 过滤器
array.filter(function(currentValue, index, arr){})
创建一个新的数组,新数组里面的元素是通过筛选后的结果
即,filter()
是筛选产生新的数组
用法结构和参数意义和上面一样
let arr = [10,20,30,40];
let newArr = arr.filter(function(value, index){
return value >= 20;
});
console.log(newArr);
(3) [20, 30, 40]
some() 有还是没有
array.some(function(currentValue, index, arr){})
检测数组中的元素是否满足条件
返回值是布尔值,找到就是true
,找不到就是false
如果找到第一个满足条件的元素,就停止循环
let arr = [10,20,30,40];
let flag = arr.some(function(value, index){
return value >= 20;
});
console.log(flag);
filter
和some
都是查找满足的元素
filter
是返回新数组,并且返回所有满足条件的元素
some
是返回布尔值,只返回找到的第一个元素
map()
创建一个新数组,该数组中的元素由原数组元素调用map函数产生。
即遍历数组元素,对他们进行函数操作,计算出一个新的数组
var array1 = [1, 2, 3, 4];
console.log(array1.map(x => x * 2)); // 输出 [ 2, 4, 6, 8 ]
every()
检测数组中是否所有元素都可以通过检测函数验证。
每一项都 true 就返回 true,否则就是 false
var array1 = [ 1, 2, 3, 4, 5 ];
console.log(array1.every(x => x < 8)); //输出 true
console.log(array1.every(x => x < 4)); //输出 false
五、ES6扩展
Array.from()
将两类对象转为真正的数组
- 类似数组的对象
- 可遍历对象
类似数组的对象
比如
{
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
}
在ES6中,可以这样转换
let arr = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arr);
arr2; //(3) ["a", "b", "c"]
常见的类似数组的对象,有DOM操作返回的NodeList集合,以及函数内部的arguments对象
也可以像map那样,后面再接收一个(函数)参数,来做一些数组的操作,比如
Array.from([1,2,3],index => index * index); //(3) [1, 4, 9]
Array.of()
将一组值转换为数组
弥补数组构造函数Array()的不足
也可以通过这个方式创建数组
const arr = Array.of(1,4,5,7,0);
arr; //(5) [1, 4, 5, 7, 0]
const arr1 = Array.of(1,3,'a','f',4,null);
arr1; //(6) [1, 3, "a", "f", 4, null]
const arr3 = Array.of();
arr3; //[]
copyWithin()
这是实例化的数组的方法,即用在一个具体的数组上
数组内部的复制,然后移动到相应的位置覆盖原来的。
会修改原数组
find() & findIndex()
数组内查找第一个符合条件的元素/位置
弥补了indexOf
方法的不能发现NaN的不足
indexof无法识别数组的NaN成员,但是findIndex
方法可以借助Object.is
方法做到。
[1,"a",NaN, 3].findIndex(y => Object.is(NaN, y))
// 2
fill()
数组的填充
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
上面代码表明,fill
方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
六、经典面试
数组扁平化
多层数组变成一层数组
[1, [2, 3, [4, 5]]] ------> [1, 2, 3, 4, 5]
1、遍历法
遍历每一个元素,然后使用不同的方法来提取元素和组合
reduce()
接受一个函数, 作为累加器,数组中从左到右的每一个值,开始缩减,最终计算为一个值。
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数 | 描述 |
---|---|
total | 必需。初始值, 或者计算结束后的返回值。 |
currentValue | 必需。当前元素 |
currentIndex | 可选。当前元素的索引 |
arr | 可选。当前元素所属的数组对象。 |
initialValue | 可选。传递给函数的初始值 |
var arr = [1,2,3,4,5];
var result = arr.reduce((total,num)=>total+num*2, 0);
console.log(result); //30
reduce函数里面传入一个箭头函数,箭头函数用来计算每个元素乘2后的累加值,整个函数就是计算2+4+6+8+10=30
map递归
递归的遍历每一项,若为数组则继续遍历,否则concat
function flatten(arr) {
var res = [];
arr.map(item => {
//如果遍历到的是数组
if(Array.isArray(item)) {
res = res.concat(flatten(item)); //递归执行这个函数,结果拼接到原来res的后面
}
//如果不是数组
else {
res.push(item); //直接添加到res里面
}
});
return res;
}
用map来遍历
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
扩展运算符
ES6的扩展运算符能将二维数组变为一维
var a = [].concat(...[1, 2, 3, [4, 5]]);
console.log(a); //(5) [1, 2, 3, 4, 5]
同样,用遍历来做一遍,把遍历到的数组使用扩展运算符
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
2、flat
Array.prototype.flat()
按指定深度递归遍历数组,并返回包含所有遍历到的元素组成的新数组。不改变原数组。
var arr1 = [ 1, 2, [ 3, 4 ] ];
console.log(arr1.flat()); // 输出 [ 1, 2, 3, 4 ]
var arr2 = [ 1, 2, [3, 4, [ 5, 6 ] ] ];
console.log(arr2.flat()); // 输出 [ 1, 2, 3, 4, [ 5, 6 ] ]
var arr3 = [1, 2, [ 3, 4, [ 5, 6 ] ] ];
console.log(arr3.flat(2)); // 输出 [ 1, 2, 3, 4, 5, 6 ]
说说数组的遍历方法
1、简单的for循环
定义变量小于数组长度
for (let i = 0; i < arr.length; i++) {
...
}
for of 遍历元素值value
for (let value of arr) {
...
}
for in 遍历索引号index
for (let index in arr) {
...
}
2、array.forEach() 方法
array.forEach(callback(currentValue, index, arr), thisArg)
传递一个回调函数,有三个参数,后面两个是可选的
无需赋值,它本身就是一个可以直接执行的函数,没有返回值
3、map 遍历
返回一个新数组,其结果是该数组中的每个元素是调用一次提供的回调函数后的返回值。
let newArray = array.map(function(currentValue, index, arr), thisArg)
传递一个回调函数,同上一样
需要函数来对元素做一些操作来改变,将改变后的元素放入新数组,有返回值
4、reduce 遍历
对数组中的每个元素执行一个由您提供的 reducer
函数(升序执行),将其结果汇总为单个返回值。
let res = array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)
要注意initialValue的值的给定,会影响开始的索引值和累加器的值
5、filter()
创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
let newArray = array.filter(function(currentValue, index, arr), thisArg)
返回的就是满足结果(通过过滤)的结果
6、every()
测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回的是一个 Boolean
类型的值。
array.every(function(currentValue, index, arr), thisArg)
都满足就是true,否则就是false
7、some()
测试数组中是不是至少有1个元素通过了被提供的函数测试,它返回的是一个 Boolean
类型的值
array.some(function(currentValue, index, arr), thisArg)
8、keys 与 values 与 entries
定义:
keys()
方法返回一个包含数组中每个索引键的 Array Iterator 对象。values()
方法返回一个新的Array Iterator
对象,该对象包含数组每个索引的值entries()
方法返回一个新的Array Iterator
对象,该对象包含数组中每个索引的键/值对。
返回的都是对象
可以遍历这些对象来看看里面究竟是什么
let arr = ['Chocolate', 'zhlll', 'lionkk'];
let itKeys = arr.keys();
let itVals = arr.values();
let itEntries = arr.entries();
for (let it of itKeys) {
console.log(it);
}
// 0
// 1
// 2
for (let it of itVals) {
console.log(it);
}
// Chocolate
// zhlll
// lionkk
for (let it of itEntries) {
console.log(it);
}
// [ 0, 'Chocolate' ]
// [ 1, 'zhlll' ]
// [ 2, 'lionkk' ]
说说改变原数组的方法
sort()
arr.sort([compareFunction])
如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
push()
将一个元素添加到数组末尾
会返回数组的长度
pop()
删除并返回数组的最后一个元素,把数组长度减 1,并且返回它删除的元素的值。
shift()
把数组的第一个元素从其中删除,并返回第一个元素的值。
unshift()
将一个或多个元素添加到数组的开头,并返回该数组的新长度
reverse()
将数组中元素的位置颠倒,并返回该数组。
splice()
通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
数组的几种映射方式
Array.map()方法
上文已经介绍
Array.from()方法
定义:通过在每个数组项上使用 callback
调用结果来创建一个新数组。
先来介绍语法:
Array.from(Array,callback(currentValue, index, arr))
简单例子:
let arr = [1, 2, 3];
let newArr = Array.from(arr, function (cur) {
return cur + 10;
})
console.log(newArr);// [ 11, 12, 13 ]