![d9159cc65cc3d29fa309406b52ee9fec.png](https://i-blog.csdnimg.cn/blog_migrate/cb94893b8f4c784894204560b9a9a491.png)
首先,我们知道Array是引用数据类型,其本质是保存在堆内存中的对象,在栈内存中保存的是对象在堆内存中的引用地址。MDN中数组的描述如下:数组是一种类列表对象。数组对象有三个属性:length、constructor和protoType。
length:表示数组的长度,即数组所包含的元素个数
constructor:表示创建数组对象的构造函数,所有数组实例的constructor都是Array
protoType:表示数组实例的原型对象
数组对象的方法有很多,这里笔者根据自己的理解归纳了9大类,逐一针对各方法的语法及使用做了简要的介绍。
![d9159cc65cc3d29fa309406b52ee9fec.png](https://i-blog.csdnimg.cn/blog_migrate/cb94893b8f4c784894204560b9a9a491.png)
我们在使用js创建数组时,通常会通过数组直接量形式或构造函数Array来创建,而ES6新增了两种创建数组的方法:Array.of()和Array.from()。
数组直接量形式创建
const arr = []; // 空数组
const arr1 = [1,2,3,4,5];
构造函数Array实例化
// 1.直接实例化
const arr = new Array(1,2,3,4,5);
console.log(arr); // [1,2,3,4,5]
// 2.实例化后赋值
const arr1 = new Array();
arr1[0] = 1;
arr1[1] = 2;
arr1[2] = 3;
arr1[3] = 4;
arr1[4] = 5;
console.log(arr1); // [1,2,3,4,5]
使用Array构造函数创建数组时,会存在一个比较奇怪的现象:构造函数在传入单个参数为整数时,所创建的数组为空数组,且数组的长度为该整数,若传入的单个参数为字符串时,所创建的数组才是包含该参数的长度为1的数组。
// 构造函数Array传入单个整数5时,此时创建的数组为[],且length为5
const arr = new Array(5);
console.log(arr); // [,,,,,] 这里是指5个空位的空数组
console.log(arr[0]); // undefined
// 构造函数Array传入单个参数为'5',此时创建的数组为['5'];
const arr1 = new Array('5');
console.log(arr1); // ['5']
为了避免Array构造函数创建数组时产生的歧义,ES6新增了Array.of()方法来创建数组
Array.of()方法创建
语法:Array.of(...args),任意个参数按顺序成为创建数组的元素。
Array.of()方法可以创建可变参数的数组实例,其不必考虑参数的数量或类型,所创建的数组元素即为所传入的参数。
const arr = Array.of(5);
console.log(arr); // [5]
const arr1 = Array.of(1,2,3,4,5);
console.log(arr1); // [1,2,3,4,5]
const arr2 = Array.of(undefined);
console.log(arr2); // [undefined]
ES6还新增了Array.from()方法,可以从类数组或可迭代对象创建一个新的,浅拷贝的数组实例。
Array.from()方法创建
语法:Array.from(arrayLike,mapFn,thisArg)
// 1.String生成数组
const str = 'string';
const arr = Array.from(str);
console.log(arr); // ['s','t','r','i','n','g']
// 2.Set生成数组
const set = new Set(['s','e','t']);
const arr1 = Array.from(set);
console.log(arr1); // ['s','e','t']
// 3.Map生成数组
const map = new Map([[1,'m'],[2,'a'],[3,'p']]);
const arr2 = Array.from(map);
const arr3 = Array.from(map.values());
const arr4 = Array.from(map.keys());
console.log(arr2); // [[1,'m'],[2,'a'],[3,'p']]
console.log(arr3); // ['m','a','p']
console.log(arr4); // [1,2,3];
// 4.类数组对象arguments生成数组
function f() {
return Array.from(arguments);
}
console.log(f(1,2,3,4,5)); // [1,2,3,4,5]
// 5.可迭代对象生成数组
const numbers = {
*[Symbol.iterator](){
yield 1;
yield 2;
yield 3;
}
}
const arr5 = Array.from(numbers,value => value +1);
console.log(arr5); // [2,3,4]
// 6.指定回调函数
const arr6 = Array.from([1,2,3,4,5], item => item * 2);
console.log(arr6); // [2,4,6,8,10]
// 7.指定回调函数及执行回调函数的this对象
const helper = {
diff:1,
add(value) {
return value + this.diff;
}
}
const arr7 = Array.from([1,2,3,4,5],helper.add,helper);
console.log(arr7); // [2,3,4,5,6]
// 8.应用:利用Array.from和Set实现数组去重
function unique(arr) {
return Array.from(new Set(arr));
}
console.log(unique([1,1,2,2,3,3,4,4,5,5])); // [1,2,3,4,5]
02
内置迭代器
ES6中有3种类型的集合对象:Array、Map集合和Set集合,这三种集合对象包括其它可迭代对象都内置了3种迭代器:
entries():返回一个迭代器,其值为多个键值对
keys():返回一个迭代器,其值为集合的所有键名
values():返回一个迭代器,其值为集合的值
了解迭代器的概念就会知道,迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,一个布尔值,当没有可返回数据时返回true。
entries()迭代器
const colors = ['red','yellow','blue'];
const iter = colors.entries();
console.log(iter.next()); // { value: [0,'red'], done: false}
console.log(iter.next()); // { value: [1,'yellow'], done: false}
console.log(iter.next()); // { value: [2,'blue'], done: false}
console.log(iter.next()); // { value: undefined, done: true}
keys()迭代器调用
const colors = ['red','yellow','blue'];
const iter1 = colors.keys();
console.log(iter1.next()); // { value: 0, done: false}
console.log(iter1.next()); // { value: 1, done: false}
console.log(iter1.next()); // { value: 2, done: false}
console.log(iter1.next()); // { value: undefined, done: true}
values()迭代器
const colors = ['red','yellow','blue'];
const iter2 = colors.values();
console.log(iter2.next()); // { value: 'red', done: false}
console.log(iter2.next()); // { value: 'yellow', done: false}
console.log(iter2.next()); // { value: 'blue', done: false}
console.log(iter2.next()); // { value: undefined, done: true}
另,Array和Set集合的默认迭代器为values(),Map集合的默认迭代器是entries(),在for...of循环中,若没有显式指定则会使用默认迭代器。
03
数组的检测与数组元素的检测
数组的检测方法有Array.isArray,数组元素的检测方法有every()、some()。
Array.isArray():用于检测一个对象是否是Array对象
语法:Array.isArray(obj)
若传入的对象是Array,则返回true,否则返回false。
console.log(Array.isArray([])); // true
console.log(Array.isArray([1])); // true
console.log(Array.isArray(new Array())); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray(undefined)); // false
every():检测数组的所有元素是否都能通过指定函数的测试,返回一个boolean值。
语法:
arr.every(callback(element,index,array),thisArg)
其中,参数element为用于检测的当前值;index可选,为当前值的索引;array可选,为调用every的当前数组。
thisArg为执行callback时使用的this对象。
[18,32,4,120,60].every(x => x > 10); // false
[18,32,14,120,60].every(x => x > 10); // true
some():检测数组中是否有一个元素能通过指定函数的测试,返回一个boolean值。
[2,1,4,8,7].some(x => x > 10); // false
[2,1,14,8,7].some(x => x > 10); // true
04
数组的重排序
数组的重排序有两种方法:sort()和reverse()
sort():用原地算法对数组的元素进行排序,并返回数组。默认的排序顺序是根据逐个字符的unicode位点进行排序。
语法:arr.sort(compareFn(firstEl, secondEl))
// 数组的升序、降序排序
const arr = [1,3,2,5,4];
console.log(arr.sort((a, b) => a - b)); // [1,2,3,4,5]
console.log(arr.sort((a, b) => b - a)); // [5,4,3,2,1]
我们知道,常见的有八大排序算法:
稳定的:冒泡排序 O(n2)、插入排序 O(n2)、基数排序 O(logRB)、归并排序 O(nlogn)。
不稳定的:选择排序 O(n2)、希尔排序 O(nlogn)、快速排序 O(nlogn)、堆排序 O(nlogn)。
这里笔者比较好奇sort()排序的底层究竟做了啥,它的算法时间复杂度又是多少呢?
不同浏览器的sort()方法的实现不同,这里主要研究了V8引擎下的sort()方法的源码,发现对于长度<=10的数组使用的是插入排序,>10的数组使用的是插入排序+快速排序。这里截取了源码的一段:
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
InsertionSort(a, from, to);
return;
}
if (to - from > 1000) {
third_index = GetThirdIndex(a, from, to);
} else {
third_index = from + ((to - from) >> 1);
}
当然,这是chrome70以前sort()的算法实现,从chrome70开始,V8团队更新了sort()方法,使用了Time-sort算法,这里笔者未作深究。
reverse():将数组中的元素颠倒,并返回该数组。该方法会改变原数组。
语法:arr.reverse()
const arr = [1,2,3,4,5];
console.log(arr.reverse()); // [1,2,3,4,5]
05数组元素的操作
针对数组的元素主要有数组元素的添加,删除和修改等操作,方法包括:
添加:push()、unshift()
删除:pop()、shift()
修改:fill()、copyWithin()
push():将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
语法:arr.push(element1,...,elementN)
push方法具有通用性,可以和call()或apply()一起使用,应用在类数组对象上。
// 添加元素到数组
const arr = [1,2,3,4,5];
const total = arr.push(6,7,8,9,10);
console.log(arr); // [1,2,3,4,5,6,7,8,9,10]
console.log(total); // 10 total为数组的新长度值
// 利用apply()合并两个数组
const arr1 = [1,2,3,4,5];
const arr2 = [6,7,8,9,10];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1); // [1,2,3,4,5,6,7,8,9,10]
// 类数组对象的应用
const obj = {
length: 0,
addElem: function(elem){ [].push.call(this, elem) }
};
obj.addElem({});
obj.addElem({});
console.log(obj); // { 0: {}, 1: {}, length: 2, addElem: ƒ}
pop():删除数组中的最后一个元素,并返回该元素。当数组为空时,返回undifined。
语法:arr.pop()
pop方法也具有通用性,可以和call()或apply()一起使用,应用在类数组对象上。
// 删除数组的最后一个元素
const arr = [1,2,3,4,5];
const elem = arr.pop();
console.log(arr); // [1,2,3,4]
console.log(elem); // 5
unshift():将一个或多个元素添加到数组的开头,并返回该数组的新长度。
语法:arr.unshift(element1,...,elementN)
// 添加元素到数组
const arr = [1,2,3,4,5];
const total = arr.unshift(6,7,8,9,10);
console.log(arr); // [6,7,8,9,10,1,2,3,4,5]
console.log(total); // 10
// 合并数组
const arr1 = [1,2,3,4,5];
const arr2 = [6,7,8,9,10];
Array.prototype.unshift.apply(arr1,arr2);
console.log(arr1); // [6,7,8,9,10,1,2,3,4,5];
shift():删除数组中的第一个元素,并返回该元素。当数组为空时,返回undefined。
语法:arr.shift()
const arr = [1,2,3,4,5];
const elem = arr.shift();
console.log(arr); // [2,3,4,5]
console.log(elem); // 1
我们知道,栈的特点是后进先出,队列的特点是后进后出。因此,我们可以利用数组的push()、pop()实现栈结构,push()、shift()实现队列结构。
// 栈结构 后进先出
const Stack = function() {
this.data = [];
this.insert = push;
this.delete = pop;
this.clear = clear;
this.length = length;
}
const push = function(element) {
this.data.push(element);
return this.data.length;
}
const pop = function() {
return this.data.pop();
}
const clear = function() {
this.data.length = 0;
}
const length = function() {
return this.data.length;
}
const s = new Stack();
s.insert('first');
s.insert('second');
console.log(s.data); // ['first','second']
s.delete();
console.log(s.data); // ['first']
s.clear();
console.log(s.data); // []
// 队列结构 后进后出
const Queue = function() {
this.data = [];
this.insert = push;
this.delete = shift;
this.clear = clear;
this.length = length;
}
const push = function(element) {
return this.data.push(element);
}
const shift = function() {
return this.data.shift();
}
const clear = function() {
this.data.length = 0;
}
const length = function() {
return this.data.length;
}
const q = new Queue();
q.insert('first');
q.insert('second');
console.log(q.data); // ['first','second']
q.delete();
console.log(q.data); // ['second']
q.clear();
console.log(q.data); // []
再进一步思考,我们可以通过栈来实现DFS:首先将根节点入栈,然后出栈后检查此节点是否有子节点,有子节点就逆序推入栈中,再出栈,子节点逆序入栈,依次循环;通过队列实现BFS:首先将根节点入队列,然后出队列检查此节点是否有字节的,有子节点就顺序入队列,再出队列子,节点顺序入队列,依次循环。
// 栈实现DFS
function deepTraversal(node) {
const nodelist = [];
if(node) {
const stack = [];
stack.push(node); // 根节点入栈
while(stack.length !== 0) {
const childItem = stack.pop(); // 出栈(数组的最后一个元素)
nodelist.push(childItem);
const childrenList = childItem.children;// 获取出栈的节点的子节点,保证子节点先出栈
for(let i = childrenList.length-1;i >= 0;i--) {
stack.push(childrenList[i]); // 子节点逆序入栈
}
}
return nodelist;
}
}
// 队列实现BFS
function wideTraversal(node) {
const nodelist = [];
if(node) {
const queue = [];
queue.push(node); // 根节点入队列
while(queue.length !== 0) {
const childItem = queue.shift(); // 出队列(数组第一个元素)
nodelist.push(childItem);
const childrenList = childItem.children; // 获取出队列的节点的子节点
for(let i = 0;i <= childrenList.length -1;i++) {
queue.push(childrenList[i]); // 子节点顺序入队列,保证父节点先出队列
}
}
return nodelist;
}
}
fill():用一个固定值填充一 个数组从起始索引到终止索引(即替换数组的指定位置的元素),不包括终止索引。返回修改后的数组。
语法:arr.fill(value, start, end)
// 队列实现BFS
const arr1 = [1,2,3,4,5].fill(4);
const arr2 = [1,2,3,4,5].fill(4,1,2);
const arr3 = [1,2,3,4,5].fill(4,4,4);
const arr4 = [1,2,3,4,5].fill(4,-2);
const arr5 = [1,2,3,4,5].fill(4,-4,-1);
const arr6 = Array(5).fill(4);
const arr7 = [].fill.call({length: 5},4);
console.log(arr1); // [4,4,4,4,4]
console.log(arr2); // [1,4,3,4,5]
console.log(arr3); // [1,2,3,4,5]
console.log(arr4); // [1,2,3,4,4]
console.log(arr5); // [1,4,4,4,5]
console.log(arr6); // [4,4,4,4,4]
console.log(arr7); // {0: 4, 1: 4, 2: 4, 3: 4, 4: 4, length: 5}
copyWithin():浅拷贝数组的一部分到同数组中的另一个位置,并返回它,不会改变原数组的长度。返回改变后的数组。
语法:arr.copyWithin(target, start, end)
const arr1 = [1,2,3,4,5].copyWithin(-2);
const arr2 = [1,2,3,4,5].copyWithin(0,3);
const arr3 = [1,2,3,4,5].copyWithin(0,3,4);
const arr4 = [1,2,3,4,5].copyWithin(3,1,4);
const arr5 = [1,2,3,4,5].copyWithin(1,-3,-1);
const arr6 = [1,2,3,4,5].copyWithin(1,-3,-4);
const arr7 = [].copyWithin.call({length: 5, 3: 1},0,3);
console.log(arr1); // [1,2,3,1,2]
console.log(arr2); // [4,5,3,4,5]
console.log(arr3); // [4,2,3,4,5]
console.log(arr4); // [1,2,3,2,3]
console.log(arr5); // [1,3,4,4,5]
console.log(arr6); // [1,2,3,4,5]
console.log(arr7); // {0: 1, 3: 1, length: 5}
06
数组元素的查找和过滤
js中数组针对数组某个元素的查找,有indexOf()、lastIndexOf()以及ES6新增的find()、findIndex()方法等;filter()可以针对数组查找符合某个条件的所有元素。
indexOf():返回指定元素在数组中的第一个的索引,若不存在,则返回-1。从数组的前面向后查找。
语法:arr.indexOf(searchElment , fromIndex)
// 查找元素在数组中的位置
const arr = [1,2,3,4,5];
console.log(arr.indexOf(2)); // 1
console.log(arr.indexOf(6)); // -1
console.log(arr.indexOf(3,3)); // -1
console.log(arr.indexOf(2,-1)); // -1
console.log(arr.indexOf(4,-3)); // 3
lastIndexOf():返回指定元素在数组中的最后一个的索引,若不存在,则返回-1。从数组的后面向前查找。
语法:arr.lastIndexOf(searchElement, fromIndex)
const arr = [1,2,3,4,5,3,1];
console.log(arr.lastIndexOf(3)); // 5
console.log(arr.lastIndexOf(6)); // -1
console.log(arr.lastIndexOf(3,3)); // 2
console.log(arr.lastIndexOf(3,-3)); // 2
console.log(arr.lastIndexOf(3,-1)); // 5
includes():查找一个数组是否包含指定元素,若包含则返回true,否则返回false。
语法:arr.incluedes(searchElement, fromIndex)
arr = [1,2,3,4,5];
console.log(arr.includes(1)); // true
console.log(arr.includes(3,2)); // true
console.log(arr.includes(3,-2)); // false
console.log(arr.includes(5,-10)); // true
find():返回数组中满足提供测试的测试函数的第一个元素的值,若没有则返回undefined。
语法:
arr.find(callback(element, index, array),thisArg)
// 用对象的属性查找数组里的某个对象
const inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
]
console.log(inventory.find(fruit => fruit.name === 'cherries'));
// {name: 'cherres', quantity: 5}
// 寻找数组中的首个质数
function isPrime(element) {
let start = 2;
while(start <= Math.sqrt(element)) {
if(element % start++ return false;
}
}
return element > 1;
}
console.log([4,6,8,12].find(isPrime)); // undefined
console.log([4,5,8,12].find(isPrime)); // 5
console.log([3,4,5,7,8,12].find(isPrime)); // 3
findIndex():返回数组中满足提供的测试函数的第一个元素的索引。若没有则返回-1。
语法:
arr.findIndex(callback(element, index, array), thisArg)
// 查找数组中首个质数元素的索引
function isPrime(element) {
let start = 2;
while(start <= Math.sqrt(element)) {
if(element % start++ return false;
}
}
return element > 1;
}
console.log([4,6,8,12].findIndex(isPrime)); // -1
console.log([4,6,7,12].findIndex(isPrime)); // 2
console.log([4,5,6,7,12].findIndex(isPrime)); // 1
filter():创建一个新数组,其包含通过所提供函数的测试的所有元素
语法:
arr.filter(callback(element, index, array), thisArg)
// 筛选满足条件的元素
const arr = [12,5,10,24,48];
const arr1 = arr.filter(element => element > 10);
const arr2 = arr.filter(element => element <= 10);
console.log(arr1); // [12,24,48]
console.log(arr2); // [5,10]
// 过滤json中的无效条目
const arr = [
{ id: 15 },
{ id: -1 },
{ id: 0 },
{ id: 3 },
{ id: 12.2 },
{ },
{ id: null},
{ id: NaN },
{ id: 'undefiend' }
];
let invalidEntries = 0;
function filterByID(item) {
if(item.id !== undefined
&& typeof(item.id) === 'number'
&& !isNaN(item.id)
&& item.id !== 0) {
return true;
}
invalidEntries++;
return false;
}
const newArr = arr.filter(filterByID);
console.log(newArr); // [{id: 15},{id: -1},{id: 3},{id: 12.2}]
console.log(invalidEntries); // 5
07
数组的合并与切割
js提供了数组的合并和分割的方法,可以针对一个或多个数组进行操作。合并的方法有:concat()、join();切割的方法有:slice()、splice()。
concat():合并两个或多个数组。此方法不改变原数组,返回一个新数组。
语法:newArr = oldArr.concat(Array1,...,ArrayN)
// 合并多个数组
const arr1 = [1,2,3];
const arr2 = [4,5,6];
const arr3 = ['a','b','c'];
const arr = arr1.concat(arr2,arr3);
console.log(arr); // [1,2,3,4,5,6,'a','b','c']
// 返回原数组的浅拷贝
const oldArray = [
{
person: {
name: 'zhang',
age: 28
},
city: 'wuhan'
},
{
person: {
name: 'wang',
age: 29
},
city: 'shenzheng'
}
]
const newArray = oldArray.concat();
oldArray[0].person.age = 27;
console.log(newArray);
// [{person: {name:'zhang',age:27},city:'武汉'},{person:{name:'wang',age:29},city:'深圳'}]
join():按指定分隔符合并数组或类数组对象的所有元素,连接成一个字符串并返回。若数组只有一个项目,那么返回时不使用分隔符。
语法:arr.join(separator)
// 连接数组
const arr = ['Winter',undefined,'Is',null,'Comming'];
const str = arr.join();
const str1 = arr.join(',');
const str2 = arr.join('_');
const str3 = arr.join('');
console.log(str); // Winter,,Is,,Comming
console.log(str1); // Winter,,Is,,Comming
console.log(str2); // Winter__Is__Comming
console.log(str3); // WinterIsComming
// 连接类数组对象
function f(a,b,c) {
const s = Array.prototype.join.call(arguments);
console.log(s);
}
f(1,'cold',true); // 1,cold,true
slice():返回一个新的数组对象,这个对象是由begin和end决定的原数组的浅拷贝(包含begin,不包含end)。原数组不改变。
语法:arr.slice(begin, end)
// 返回现有数组的一部分
const arr = ['Banana','Orange','Lemon','Apple','Mango'];
const fruit = arr.slice();
const fruit1 = arr.slice(1,3);
const fruit2 = arr.slice(-1,3);
const fruit3 = arr.slice(3,-1);
const fruit4 = arr.slice(-1,-3);
const fruit5 = arr.slice(-3,-1);
console.log(fruit); // ['Banana','Orange','Lemon','Apple','Mango']
console.log(fruit1); // ['Orange','Lemon']
console.log(fruit2); // []
console.log(fruit3); // ['Apple']
console.log(fruit4); // []
console.log(fruit5); // ['Lemon','Apple']
// 类数组对象调用
function list() {
return [].slice.call(arguments);
}
list(1,2,3,4,5); // [1,2,3,4,5]
splice():通过删除或替换现有数组的元素或原地添加新的元素来修改数组,并以数组的形式返回被修改的内容。此方法会改变原数组。返回值为被删除的元素组成的数组。
语法:arr.splice(start, deleteCount, item1,item2,...)
const arr1, arr2, arr3, arr4, arr5 = [1,2,3,4,5];
console.log(arr1.splice(2)); // [3,4,5]
console.log(arr1); // [1,2]
console.log(arr2.splice(1,5)); // [2,3,4,5]
console.log(arr2); // [1]
console.log(arr3.splice(-1,3,4,5)); // [5]
console.log(arr3); // [1,2,3,4,4,5]
console.log(arr4.splice(-1,-1,4,5)); // []
console.log(arr4); // [1,2,3,4,5,4,5]
console.log(arr5.splice(6,2,4,5)); // []
console.log(arr5); // [1,2,3,4,5,4,5]
08数组的遍历
js中遍历数组的方法有很多,主要有:forEach()、map()、reduce()、reduceRight()。
forEach():遍历数组的每个元素,执行一次给定的函数。forEach除非抛出异常,否则无法跳出循环,且不对未初始化的值进行任何操作。返回值为undefined。
语法:
arr.forEach(callback(currentValue, index, array), thisArg)
// 遍历稀疏数组
const arrSparse = [1,3,,7];
let numCallbackRuns = 0;
arrSparse.forEach(function(element) {
console.log(element);numCallbackRuns++;
});
console.log('numCallbackRuns: ',numCallbackRuns);
// 1
// 3
// 7
// numCallbackRuns: 3
map():创建一个新数组,其结果是遍历数组的每个元素,执行指定的函数后的返回的值。不会改变原数组。
语法:
// 求数组中每个元素的平方
const arr = [1,2,3,4,5];
const newArr = arr.map(item => Math.pow(item,2));
console.log(newArr); // [1,4,9,16,25]
// map格式化数组中的对象
const arr = [
{key: 1, value: 10},
{key: 2, value: 20},
{key: 3, value: 30}
];
const newArr = arr.map(function(obj) {
const rObj = {};
rObj[obj.key] = obj.value;
return rObj;
})
console.log(newArr); // [{1: 10},{2: 20},{3: 30}]
reduce():对数组中的每个元素执行一个指定的reducer函数,将其结果汇总为单个返回值。
语法:
// 累加数组里的所有值
const arr = [1,2,3,4,5];
const total = arr.reduce((acc,cur) => acc + cur, 0);
console.log(total); // 15
// 将二维数组转化为一维数组
const arr1 = [[1,2],[3,4],[5,6]];
const flattened = arr1.reduce((acc, cur) => acc.concat(cur), []);
console.log(flattened); // [1,2,3,4,5,6]
// 计算数组中每个元素出现的次数
const names = ['Alice', 'Bob', 'Tiff','Bruce', 'Alice'];
const countNames = names.reduce(function(allNames, name){
if(name in allNames){
allNames[name]++;
} else {
allNames[name] = 1;
}
return allNames
},{});
console.log(countNames); // {'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1}
// 数组去重
const arr2 = [1,3,5,7,5,3,1];
const newArr = arr2.reduce((acc, cur) => {
if(!acc.includes(cur)) {
acc.push(cur)
}
return acc;
}, []);
console.log(newArr); // [1,3,5,6]
reduceRight():接受一个函数作为累加器,从右到左遍历数组的元素,将其结果汇总为单个值。
语法:
arr.reduceRight(callback(accumulator,currentValue,index,array),initialValue)
// 计算数组元素的和
const arr = [0,1,2,3,4];
const sum = arr.reduceRight((acc, cur) => acc + cur, 0);
console.log(sum); // 10
// 扁平化一个二维数组
const arr2 = [[0,1],[2,3],[4,5]];
const flattened = arr2.reduceRight((acc, cur) => acc.concat(cur));
console.log(flattened); // [4,5,2,3,0,1]
// reduce与reduceRight的区别
const arr3 = ['1','2','3','4','5'];
const arr4 = arr3.reduce((acc, cur) => acc + cur);
const arr5 = arr3.reduceRight((acc, cur) => acc + cur);
console.log(arr4); // '12345'
console.log(arr5); // '54321'
09数组扁平化
js中,可能存在这样中情况,比如数组中嵌套了数组(即数组的元素仍是数组),当我们想将所有的元素展开组成一个一维数组,即数组扁平化。那么此时就要用到flat()或flatMap()方法。
flat():按照一个指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组。
语法:newArr = arr.flat(depth)
// 扁平化嵌套数组
const arr1 = [1,2,[3,4]];
const arr2 = arr1.flat();
console.log(arr2); // [1,2,3,4]
const arr3 = [1,2,[3,4,[5,6]]];
const arr4 = arr3.flat();
const arr5 = arr3.flat(2);
console.log(arr4); // [1,2,3,4,[5,6]]
console.log(arr5); // [1,2,3,4,5,6]
// 使用Infinity可展开任意深度的嵌套数组
const arr6 = [1,2,[3,4,[5,6,[7,8,[9,10]]]]];
const arr7 = arr6.flat(Infinity);
console.log(arr7); // [1,2,3,4,5,6,7,8,9,10]
// 扁平化会移除数组空项
const arr8 = [1,2,,4,5];
const arr9 = arr8.flat();
console.log(arr9); // [1,2,4,5]
当然,我们也可以通过递归 + isArray来扁平化嵌套数组:
const arr = [1,2,3,[1,2,3,[1,2,3,[1,2,3]]]];
function flatten(arr) {
return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur)?flatten(cur):cur),[])
}
console.log(flatten(arr)); // [1,2,3,1,2,3,1,2,3,1,2,3]
flatMap():首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与map连着深度值为1的flat几乎相同,但效率更高。
语法:
arr.flatMap(callback(currentValue,index,array),thisArg)
// map()与flatMap()的区别
const arr = [1,2,3,4,5];
const arr1 = arr.map(x => [x * 2]);
const arr2 = arr.flatMap(x => [x * 2]);
const arr3 = arr.flatMap(x => [[x * 2]]);
console.log(arr1); // [[2],[4],[6],[8],[10]]
console.log(arr2); // [2,4,6,8,10]
console.log(arr3); // [[2],[4],[6],[8],[10]]
【参考文献】:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
![63cad393e87e971b56fd061cad91d809.gif](https://i-blog.csdnimg.cn/blog_migrate/9e7062346565070f2d834d83224463b4.gif)
![2d23c014d1a68605063c6125ed8d5094.gif](https://i-blog.csdnimg.cn/blog_migrate/42ed10299759390d61d8bf66809e5e01.gif)
![dddb334149ab27f65f053a8f1b02732e.gif](https://i-blog.csdnimg.cn/blog_migrate/c77877127a01c88402a674e1cafd44e8.gif)