一、数组排序
1. sort 方法
sort():是对数组元素进行排序,默认排序顺序是 先将元素转换为字符串,然后再按照转换为字符串的各个字符的 Unicode(字符编码) 位点进行排序进行排序
sort(function(){}):可对数字排序
var arr = new Array('1','3','8','55','2','3','5','66');
arr = arr.sort();
console.log(arr.toString()) // 1,2,3,3,5,55,66,8
2. sort 降序、升序排列
let arr = [66, 55, 888,444, 222, '111', 1114,'2222']
// 等价于 arr.sort((a, b)=>b-a)
arr.sort(function(a,b){
return a-b
})
console.log([...new Set(arr)]);
// [66, 55, 888, 444, 222, '111', 1114, '2222']
/*
* return b-a; —> 降序排序
* return a-b; —> 升序排列
*/
3.倒叙 reverse()
var array=['我','喜','欢','你'];
array.reverse(); // ['你', '欢', '喜', '我']
4.冒泡排序
就是把一组乱序的数组排成一个整齐的数组,一种基础的排序算法
核心逻辑(正序):把数组中的前两个数据拿来比较,如果前面的数大于后面的数,那么就进行位置交换,如果前面的数没有后面的大,就不交换位置。
步骤:先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置。 数组遍历一遍以后,最后的一个数字就是最大的那个。然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二的位置。以此类推,最后就会按照顺序把数组排好了。
/*
* 总共比较次数为arr.length-1次
* 每次的比较次数为arr.length-1次
* 依次递减
*/
var arr = [10, 20, 40, 60, 60, 0, 30]
var temp;//交换变量标识
// 两层for分别表示当前项与第二项
for(let i = 0; i < arr.length - 1; i++) {
for(let j = 0; j < arr.length - 1; j++) {
// 如果当前项大于第二项(后一项)则交换
if(arr[j] > arr[j+1]) {
temp = arr[j]
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 打印排序后的数组
console.log(arr)//[0, 10, 20, 30, 40, 60, 60]
5.希尔排序
希尔排序思路: 将无序数组分割成若干子序列,子序列不是逐段分割的,而是相隔特定增量的子序列,对各个子序列进行插入排序,然后再选择一个更小的增量,再将之前排序后的数组按这个增量分割成多个子序列,...,不断选择更小增量,直到增量为1时,再对序列进行一次插入排序,使序列最终成为有序序列,排序完成。
所以关键是确认一个有规律的逐渐递减的增量,这里的首选增量为n/2,每次增量为原先的1/2,直到增量为1
第二层循环为什么循环从 增量开始然后递增呢? 从增量开始,减去增量本身,得到的就是与该元素相差增量个的前一个元素 增量依次递增,每次减去增量本身,就依次得到了与该元素相差增量个的每一个元素
function shellSort(arr) {
const len = arr.length;
// 增量为每次递减二分之一的数
for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
// 对以增量为间隔所形成的子序列进行插入排序
// 为什么循环从 增量开始然后递增呢?
// 从增量开始,减去增量本身,得到的就是与该元素相差增量个的前一个元素
// 增量依次递增,每次减去增量本身,就依次得到了与该元素相差增量个的每一个元素
for (let i = gap; i < len; i++) {
// 得到与该元素相差增量个的前一个元素
let j = i - gap;
// 插入排序是要移动数组的,防止要插入的元素被覆盖掉
let temp = arr[i];
// 间隔增量个的前面的元素更大,就往后移动
while (j >= 0 && temp < arr[j]) {
arr[j + gap] = arr[j];
j = j - gap;
}
// 循环结束,证明循环结束位置的元素比要插入的元素小
// 所以循环结束位置的下一个位置就是要插入的位置
arr[j + gap] = temp;
}
}
}
let list = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48];
shellSort(list)
console.log(list);
//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
一、数组扁平化
数组扁平化就是将一个多维数组转换为一个一维数组
实现思想
- 对数组的每一项进行遍历。
- 判断该项是否是数组。
- 如果该项不是数组则将其直接放进新数组。
- 是数组则回到1,继续迭代。
- 当数组遍历完成,返回这个新数组。
1. 使用数组 concat方法
var arr= [[0,0,1],[2,3,3],[4,4,5]];
var newArr = [];
for(var i=0;i<arr.length;i++){
newArr=newArr.concat(arr[i])
}
console.log(arr) //[[0,0,1],[2,3,3],[4,4,5]];
console.log(newArr) // [0, 0, 1, 2, 3, 3, 4, 4, 5]
2. 数组 join 方法
但是有一个缺点就是使数组每一项都变成了字符串
var arr=[1,[2,[[3,4],5],6]];
function getArr(arr){
return arr.join().split(",");
}
console.log(getArr(arr)); // ['1', '2', '3', '4', '5', '6']
3. 递归
var arr = [1,[2,[[3,4],5],6]];
var newArr = [];
function fun(arr){
for(var i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
fun(arr[i]);
}else{
newArr.push(arr[i]);
}
}
}
fun(arr);
console.log(newArr);//[1, 2, 3, 4, 5, 6]
4. for in循环 递归
其实第四种跟第三种差不多,换用写法而已
var arr =[1,[2,[[3,4],5],6]];
var newArr=[];
function getArr(arr) {
for(var k in arr) {
if( arr[k] instanceof Array) {
getArr (arr[k]);
}else { newArr.push(arr[k]);
}
}
return newArr;
}
console.log(getArr(arr));
二、数组去重
1. 由对象组成的数组去重
var o = {};
[{name: '33'}, {name: '55'}].forEach(item => {
o[item.name] = item;
})
Object.values(o)
2. 去重:遍历数组法
var arr = [2, 8, 5, 0, 5, 2, 6, 7, 2]
var newArr = []
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i])
}
}
console.log(newArr) // 结果:[2, 8, 5, 0, 6, 7]
3. 去重:数组下标判断法
var arr = [2, 8, 5, 0, 5, 2, 6, 7, 2]
var newArr = []
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) === i) {
newArr.push(arr[i])
}
}
console.log(newArr) // 结果:[2, 8, 5, 0, 6, 7]
看 if 这里,在遍历 arr 的过程中,如果在 arr 数组里面找当前的值,返回的索引等于当前的循环里 面的 i 的话,那么证明这个值是第一次出现,所以推入到新数组里面
如果后面又遍历到了一个出现过的值,那也不会返回它的索引,indexof() 方法只返回找到的第一个值的索引,所以重复的都会被 pass 掉,只出现一次的值都被存入新数组中,也达到了去重的目的。
4. 去重:排序后相邻去除法
这种方法用到了 sort( ) 方法,代码如下:
var arr = [2, 8, 5, 0, 5, 2, 6, 7, 2]
arr.sort()
var newArr = [arr[0]]
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== newArr[newArr.length - 1]) {
newArr.push(arr[i])
}
}
console.log(newArr) // 结果:[0, 2, 5, 6, 7, 8]
这种方法的思路是:
先用 sort() 方法把 arr 排序,那么排完序后,相同的一定是挨在一起的, 把它去掉就好了,
首先给新数组初始化一个 arr[0],因为我们要用它和 arr 数组进行比较
所以,for 循环里面 i 也是从 1 开始了,我们让遍历到的 arr 中的值和新数组最后一位进行比较,如果相等,则 pass 掉,不相等的,push 进来,
因为数组重新排序了,重复的都挨在一起,那么这就保证了重复 的这几个值只有第一个会被 push 进来,其余的都和新数组的被 push 进来的这个元素相等,会被 pass 掉,也达到了去重的效果。
5. 去重:利用ES6 Set去重
Set 数据结构,它类似于数组,其成员的值都是唯一的。 利用 Array.from 将 Set 结构转换成数组
function unique (arr) {
return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
6. 去重:优化的遍历数组法
var arr = [2, 8, 5, 0, 5, 2, 6, 7, 2, 8]
var newArr = []
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
i++
j = i
}
}
newArr.push(arr[i])
}
console.log(newArr) // 结果:[0, 5, 6, 7, 2, 8]
思路: 两层 for 循环,外面一层是控制遍历到的前一个 arr 中的元素,里面一层控制的是第一层访问到 的元素后面的元素,不断的从第 0 个开始,让第 0 个和他后面的元素比较,如果没有和这个元素相等的, 则证明没有重复,推入到新数组中存储起来,如果有和这个元素相等的,则 pass 掉它,直接进入下一次 循环。
从第 1 个开始,继续和它后面的元素进行比较,同上进行,一直循环到最后就是:不重复的 都被推入新数组里面了,而重复的前面的元素被 pass 掉了,只留下了最后面的一个元素,这个时候也就 不重复了,则推入新数组,过滤掉了所有重复的元素,达到了去重的目的。
7. 去重:数组遍历法
var arr = ['a', 'a', 'b', 'c', 'b', 'd', 'e', 'a']
var newArr = []
for (var i = 0; i < arr.length; i++) {
var bl = true
for (var j = 0; j < newArr.length; j++) {
if (arr[i] === newArr[j]) {
bl = false
break
}
}
if (bl) {
newArr.push(arr[i])
}
}
console.log(newArr) // 结果:["a", "b", "c", "d", "e"]
思路:
也是两层 for 循环,外层 for 循环控制的是 arr 数组的遍历,内层 for 循环控制的是新数组的
遍历,
从第 0 位开始,如果新数组中没有这个 arr 数组中遍历到的这个元素,那么状态变量 bl
的值还是 true,那么自然进入到了 if 中把这个值推入到新数组中,如果有这个元素,那么代表重复,
则把状态变量 bl 取值改为false,并且跳出当前循环,不会进入到 if 内部,而进入下一次
外层开始的循环。这样循环往复,最后也达到了去重的效果。
三. 不改变原数组的方法
1. slice (截取数组)
slice(start, end) 方法可从已有的数组中返回选定的元素,组成一个新的数组。
- 如果不传参数,会返回原数组
- 如果一个参数,从该参数表示的索引开始截取,直至数组结束,返回这个截取数组
- 如果两个参数,从第一个参数对应的索引开始截取,到第二个参数对应的索引结束,start 包含,end 不包含
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]
var citrus = fruits.slice(1,3)
console.log(citrus) // ["Orange","Lemon"]
2. concat ( 联合数组 )
concat()方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
var hege = ["Cecilie", "Lone"];
var stale = ["Emil", "Tobias", "Linus"];
var kai = ["Robin"];
var children = hege.concat(stale,kai);
*children* 的输出结果: Cecilie,Lone,Emil,Tobias,Linus,Robin
concat()不会进行去重,但是我们可以封装一个合并数组并去重的方法, 使用函数调用参数,来对数组进行 concat 合并处理指向 apply 调用 this 执行函数
function combine(){
//这里是没有去重,是进行合并数组
let arr=[].concat.apply([],arguments);
//set 可以过滤掉重复的数字
return Array.from(new Set(arr));
}
var m =[1,2,3,2],
n=[2,3,4];
console.log(combine(m,n)) // [1, 2, 3, 4]
3. join (将数组转换成字符串)
join() 方法用于把数组中的所有元素转换一个字符串。 元素是通过指定的分隔符进行分隔的。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var energy = fruits.join(); // Banana,Orange,Apple,Mango
4. for 循坏
for 方法跳出循环-----break 跳出循环 ; continue 跳出当次循环
var arr=[1,3,5,7,9];
var id = 5;
for(var i=0;i<arr.length;i++){
if(arr[i]===1)continue;
console.log(arr[i])
if(arr[i]===id){
break;
}
}
5. forEach 循坏
forEach方法跳出循环----通过抛出异常的方式 try...catch...跳出循环; 通过 return 跳过当次循环
var arr=[1,3,5,7,9];
var id = 5;
try{
arr.forEach(function(curItem,i){
if(curItem===1)return;
console.log(curItem);
if(curItem===id){
throw Error();
}
})
}catch(e){
console.log(e)
}
6. for和 forEach 的区别
1.forEach() 不能使用 break 和 continue 这两个关键字,它实现 break 效果可以通过抛出异常的方式,实现 continue 的效果可以直接使用 return
2.forEach 的优势就是,它传入一个函数,因此形成了一个作用域,它内部所定义的变量不会像 for 循环一样污染全局变量
3.forEach() 本身无法跳出循环,必须遍历所有的数据才能结束
4.for 方法跳出循环-----break跳出循环 continue跳出当次循环
5. map 与 foreach 的区别
1、相同点
- 都是循环遍历数组中的每一项。
- 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)。
- 匿名函数中的 this 都是指向 window。
- 只能遍历数组。
2、不同点
- map( ) 会分配内存空间存储新数组并返回,forEach() 不会返回数据。
- forEach( ) 允许 callback 更改原始数组的元素。map() 返回新的数组。
6. map ( )
map( )返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
var array1 = [1,4,9,16];
const map1 = array1.map(x => x *2);
console.log(map1); // [2,8,18,32]
7. filter ()
会创建一个新数组,原数组的每个元素传入回调函数中,回调函数中有 return 返回值,若返回值为 true,这个元素保存到新数组中;若返回值为 false,则该元素不保存到新数组中
注意:filter() 不会对空数组进行检测;不会改变原始数组
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let res = nums.filter((num) => {
return num > 5;
});
console.log(res); // [6, 7, 8, 9, 10]
8. reduce()
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
let 结果 = 数组.reduct(累加器, 初始化值)
//累加器
(累加结果, 当前值, 当前索引)=>{
return 处理结果
}
// 累加和
// reduce 案例1:累加和
let arr = [1,2,3,4,5]
let s = arr.reduce( (sum,current,index)=>{
return sum + current
} , 0)
console.info(s)
//案例2:对象数组的累加和
let arr = [
{
name: 'jack',
count: 10
},
{
name: 'rose',
count: 20
}
]
let s = arr.reduce((sum,current,index)=>{
return sum + current.count
},0);
console.info(s)
//案例2:对象数组的累加和
let arr = [
{
name: 'jack',
count: 10
},
{
name: 'rose',
count: 20
}
]
let s = arr.reduce((sum,current,index)=>{
return sum + current.count
},0);
console.info(s)
//案例3:
let arr = [
{name: 'jack',course:'语文',count: 100},
{name: 'jack',course:'英语',count: 100},
{name: 'jack',course:'数学',count: 100},
{name: 'rose',course:'语文',count: 50},
{name: 'rose',course:'英语',count: 50},
{name: 'rose',course:'数学',count: 50}
]
//reduce
let s2 = arr.reduce((obj,current,index)=>{
let name = current.name
let count = current.count
// 获得obj对应名称值 {'jack':100} --》 100
let oldCount = obj[name]
// oldCount 如果是 undefined,表示此名称第一次出现
if(oldCount){
obj[name] = oldCount + count
} else {
//第一次赋值
obj[name] = count
}
console.info(`之前累加值:${oldCount},当前值:${count},最终结果:${JSON.stringify(obj)}`)
return obj
} , {})
//结果:{'jack': 300, 'rose': 150}
/*没有数据:{}
{'jack': 100}
{'jack': 200}
{'jack': 300}
{'jack': 300,'rose':50}
{'jack': 300,'rose':100}
{'jack': 300,'rose':150}
*/
console.info(s2)
9. some()
检测数组中是否含有某一个值,如果数组中有任意一个元素满足给定的条件,结果为 true, 否则为 false
var arr = [32, 33, 16, 40]
var newArr = arr.some((item,index,arr)=>{
return item >= 18
})
console.log(arr) // [32, 33, 16, 40]
console.log(newArr) // true
四. 改变原数组的方法
1. push() unshift() 返回数组的长度
var arr = [1,2,3,4]
var a = arr.unshift(9,8,7)
console.log('a='+a+' arr='+arr) // a=7 arr=9,8,7,1,2,3,4
2. pop() 方法用于删除并返回数组的最后一个元素。
var arr = [4,3,2,3]
var a = arr.pop()
console.log('a='+a+' arr='+arr) // a=3 arr=4,3,2
3. shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
let arr = [1, 2,3]
let a = arr.shift();
console.log(a); // 1
console.log(arr) // [2,3]
4. reverse() 方法用于颠倒数组中元素的顺序。
var fruits = ["Banana", "Orange", "Apple", "Mango"]
fruits.reverse()
console.log(fruits) // ["Mango", "Apple", "Orange", "Banana"]
5. sort () 排序数组
let arr = ["10", "5", "40", "25", "1000", "1"];
function sortNumber (a, b) {
return a - b
}
let a = arr.sort();
let b = arr.sort(sortNumber);
console.log(a)
console.log(b)
6. splice 截取数组的同时,还会插入数据,返回的值为截取出来的元素
// 6. array.splice(index,howmany,item1,…,itemX)
// a.没有参数,返回空数组,原数组不变
// b.一个参数,从该参数表示的索引位开始截取,直至数组结束,返回截取的数组,
// 原数组改变;
// c.两个参数,第一个参数表示开始截取的索引位,第二个参数表示截取的长度,返回截取的 数组,
原数组改变;
// d.三个或者更多参数,第三个及以后的参数表示要从截取位插入的值。
var fruits = ["Banana", "Orange", "Apple", "Mango"]
var a = fruits.splice(1,2,'Peel')
console.log(a) // ["Orange", "Apple"]
console.log(fruits) // ["Banana", "Peel", "Mango"]
五. ES5 新增的一些数组方法
1. indexOf(searchvalue,start)
字符串,数组都可适用,此方法可返回某个指定的字符串值在字符串中首次出现的位置 若一个参数,返回这个参数在数组里面的索引值,如果参数不在操作的数组中,则返回 -1。
var arr = [1,2,3,4];
arr.indexOf(1) // 0
arr.indexOf(5) // -1
2. forEach(function(item, index, arr))
数组遍历,且只能够遍历数组,不接受返回值或返回值为 undefined,单纯对数组进行循环如果数组中的值为 empty, 则不会执行回调函数
var arr = [1,2,3,4,5];
arr.forEach((item,index,arr)=>{
// item: 遍历的数组内容
// index: 对应的数组索引
// arr: 数组本身
})
3. array.map(function(item,index,arr)) (不改变原数组)
数组的遍历,用来接收一个返回值,创建一个新数组
var arr = [1,2,3,4,5,6]
var newArr = arr.map(function(item,index,arr){
return item * 2
})
console.log(arr) // [1, 2, 3, 4, 5, 6]
console.log(newArr) // [2, 4, 6, 8, 10, 12]
4. array.filter(function(item,index,arr)) (不改变原数组)
过滤出一些符合条件的元素,返回一个新数组 (返回为 true,该元素就进新数组,false反之)
var arr = [32, 33, 16, 40]
var newArr = arr.filter((item,index,arr)=>{
return item >=18
})
console.log(arr) // [32, 33, 16, 40]
console.log(newArr) // [32, 33, 40]
5. array.some(function(currentValue,index,arr)) (不改变原数组)
检测数组中是否含有某一个值,如果数组中有任意一个元素满足给定的条件,结果为 true,否则为false
var arr = [32, 33, 16, 40]
var newArr = arr.some((item,index,arr)=>{
return item >= 18
})
console.log(arr) // [32, 33, 16, 40]
console.log(newArr) // true
6. array.every(function(currentValue,index,arr)) (不改变原数组)
方法用于检测数组所有元素是否都符合指定条件(通过函数提供),返回一个布尔值,结果为 true 或 false
var arr = [32, 33, 16, 40]
var newArr = arr.every((item,index,arr)=>{
return item >=18
})
console.log(arr) // [32, 33, 16, 40]
console.log(newArr) // false
7. array.reduce(function(total, currentValue, currentIndex, arr))
对数组中的所有元素调用指定的回调函数,该回调函数的返回值为累计结果。且把返回值作为下一次回调函数的参数。
var arr = [1,2,3,4,5,6,7,8,9];
var res = arr.reduce((pre,next,index,arr1)=>{
console.log("pre:"+pre) // 前一个的值 pre: 0 1 3 6 10 15 21 28 36
console.log("next:"+next) // 后一个的值 next:1 2 3 4 5 6 7 8 9
console.log('arr1:'+arr1)
return pre+next
})
console.log("arr:"+arr) // arr:1,2,3,4,5,6,7,8,9
console.log("res:"+res) // res:45
六. ES6 数组方法
1. includes( )
includes( ) 检测数组中是否包含一个值。
[1, 2, 3].includes(1) // true
[1, 2, 3].includes(1, 2) // false 从位置索引 2 可以查找是否包含1的值
[1, NaN, 3].includes(NaN) // true
2. Array.from(arrayLike[, mapFn[, thisArg]]) 将类数组转换为数组
let array = {
0: 'name',
1: 'age',
2: 'sex',
3: ['user1','user2','user3'],
'length': 4
}
let arr = Array.from(array )
console.log(arr) // ['name','age','sex',['user1','user2','user3']]
Array.from(str) 将字符串转换为数组
let str = 'hello world!';
console.log(Array.from(str)) // ["h", "e", "l", "l", "o", " ", "w", "o", "r",
"l", "d", "!"]
3. Array.of()
数组创建,将参数中所有值作为元素形成数组,如果参数为空,则返回一个空数组
console.log(Array.of()) // []
console.log(Array.of(1, 2, 3, 4)) // [1, 2, 3, 4]
console.log(Array.of(1, '2', true)) // [1, '2', true]
4. find()
查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素
let arr = Array.of(1, 2, 3, 4)
console.log(arr.find(item => item > 2)) // 3
console.log([, 1].find(n => true)) // undefined
5. findIndex()
查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引。
var arr = Array.of(1, 2, 1, 3)
console.log(arr.findIndex(item => item == 1)); // 0
console.log([, 1].findIndex(n => true)); // 0
6. fill()
将一定范围索引的数组元素内容填充为单个指定的值。
// 参数1:用来填充的值
// 参数2:被填充的起始索引
// 参数3(可选):被填充的结束索引,默认为数组末尾
var arr1 = Array.of(1, 2, 3, 4)
var arr2 = Array.of(1, 2, 3, 4)
console.log(arr1.fill(0,1)) // [1, 0, 0, 0]
console.log(arr2.fill(0,1,3)) // [1, 0, 0, 4]
7. … 扩展运算符
把数组或对象展开一系列用逗号 (,) 隔开的值
var arr = [1, 2],
arr1 = [...arr]
console.log(arr1) // [1, 2]
// 数组含空位
var arr2 = [1, , 3],
arr3 = [...arr2]
console.log(arr3) // [1, undefined, 3]
// 合并数组
console.log([...[1, 2],...[3, 4]]); // [1, 2, 3, 4]
// es6的扩展运算符能将二维数组变为一维
[].concat(...[1, 2, 3, [4, 5]]); // [1, 2, 3, 4, 5]
七、数组其他相关
1. 数组里面有10万个数据,取第一个元素和第10万个元素的时间相差多少
数组可以直接根据索引取的对应的元素,所以不管取哪个位置的元素的时间消耗时间几乎一致,差异可以忽略不计
2. for…in 与 for…of 的区别
- 都可以遍历数组,for in 返回数组的下标(key);for of 返回数组的元素;
const arr1 = ['a', 'b', 'c'];
for (let i in arr1) {
console.log(i) // 0, 1, 2
}
const arr2 = ['a', 'b', 'c'];
for (let i of arr2) {
console.log(i) // a, b, c
}
- 遍历对象 for in 遍历获取对象 key 值; for of 报错;
const json = {"a": 1, "b": 2, "c": 3};
for (let i in json) {
console.log(i) // a, b, c
}
for (let i of json) {
console.log(i) // 数据格式错误
}
- 给数组手动添加属性, for in 循环可以遍历出 name 这个添加属性的键名
const arr3 = ['a', 'b'];
arr3.name = 'c';
for (let i in arr3) {
console.log(i) // 0, 1, name
}
- for in 的特点:
- for … in 循环返回的值都是数据结构的 键值名。
- 遍历对象返回的对象的key值;
- 遍历数组返回的数组的下标(key)。
- for … in 循环不仅可以遍历数字键名,还会遍历原型上的key值和手动添加的其他键;
- 特别情况下, for … in 循环会以任意的顺序遍历键名
- 总结一句: for in 循环特别适合遍历对象。
- for of 特点:
- for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名
- 一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator 接口, 就可以使用 for of循环。 例 3 这个对象,没有 Symbol.iterator这个属性,所以使用 for of会报json is not iterable
- for of 不同与 forEach, 它可以与 break、continue 和 return 配合使用, 也就是说 for of 循环可以随时退出循环。
- 我也想让对象可以使用 for of 循环怎么办? 使用 Object.keys() 获取对象的 key 值集合后, 再使用 for of
const obj = {a: 'x', b: 'y'};
for (let i of Object.keys(obj)) {
console.log(i) // a, b
}
3. 找出数组中出现次数最多的元素
方法 1. 利用键值对存储
实现方法1的主要思想是利用键值对存储,我们可以分解为两个步骤。
- 定义一个对象,在遍历数组的时候,将数组元素作为对象的键,将出现的次数作为值
- 获取键值对后进行遍历,获取值最大的那个元素,返回后即可得到结果。通过以上的思想,我们可以得到以下实现代码。
因为方法1会 首先对数组进行遍历,然后对对象进行遍历,在实现效率上比较低下,不推荐使用。
方法 2.主要思想同方法1,
不过是方法1的优化,将方法1中的两次遍历缩减为一次遍历,将值的判断放在同一个遍历中。
3.借助数组Array的reduce方法
首先我们来看看reduce方法的使用方法,它的语法如下。
arr.reduce([callback, initialValue])reduce方法接收的第一个参数为函数,操作数组中的每个元素。该函数接收4个参数,每个参数的含义如下。
- 第一个参数表示上一次执行结果的回调,或者第二个参数提供的初始值
- 当前处理的元素值
- 当前处理元素的索引
- 处理的数组
reduce方法接收的第二个参数为提供处理元素的初始值,与上面的第一个参数有关。
在了解 reduce 方法后,我们可以直接看看下面的代码。
4. 修改后端返回的树结构的字段名
后端给的树结构是分级的。但是字段跟组件给的对不上。 blog.csdn.net/m0_51434664…
第一种方法:修改返回的树的字段名,使用replace来筛选所有的字段,这个地方要加g,g 指的是全局,就是不管你的树有几级,他都会给你找出来并修改,要不然只会修改第一级的。简单高效。不用递归, 代码如下
var replaceStr = JSON.parse(JSON.stringify(datas.childs).replace(/"cateId"/g, '"value"').replace(/"childs"/g, '"children"'))
第二种方法:树结构组件可以自定义节点的字段,让组件去匹配你的树结构的字段
注意:级联数组去掉最后一层空数组 childern,以防最后一层显示空白。
// 递归判断列表,把最后的children设为undefined
getTreeData(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].node.length < 1) {
// children若为空数组,则将children设为undefined
data[i].node = undefined;
} else {
// children若不为空数组,则继续 递归调用 本方法
this.getTreeData(data[i].node);
}
}
return data;
},
5. 根据 相同的 key 值把多个数组合并
需求如下 ,需要把 arr1 和 arr2 根据相同的 code 值,并且其中的 cout 值进行加以区分, 转化成 arr3 的形式
# 返回数据
let arr1 = [
{ name: "无", count: 1, code: 0 },
{ name: "全新现车", count: 2, code: 1 },
{ name: "客户订单", count: 3, code: 10 },
{ name: "试驾车", count: 4, code: 7 },
{ name: "展车", count: 5, code: 8 },
];
let arr2 = [
{ name: "无", count: 67, code: 0 },
{ name: "全新现车", count: 7, code: 1 },
{ name: "客户订单", count: 40, code: 10 },
{ name: "试驾车", count: 22, code: 7 },
{ name: "展车", count: 1, code: 8 },
];
// # 期望数据
let arr3 = [
{ name: "无", arr1Count: 1, arr2Count: 67, code: 0 },
{ name: "全新现车", arr1Count: 2, arr2Count: 7, code: 1 },
{ name: "客户订单", arr1Count: 3, arr2Count: 40, code: 10 },
{ name: "试驾车", arr1Count: 4, arr2Count: 22, code: 7 },
{ name: "展车", arr1Count: 5, arr2Count: 1, code: 8 },
];
实现代码
// 数组对其中的 count 进行别名命名
function getNewList(key, list) {
let keyStr = `${key}Count`;
return list.map((ele) => {
let name = ele.name;
let code = ele.code;
return {
[keyStr]: ele.count,
code,
name,
};
});
}
// 根据 指定的 key 进行合并数据
function arrMerge(arr1, arr2 , key) {
const combined = arr1.map((item1) => {
arr2.map((item2) => {
if (item1[key] === item2[key]) {
Object.assign(item1, item2);
}
});
return item1;
});
return combined;
}
const newArr1 = getNewList( "arr1", arr1 );
const newArr2 = getNewList("arr2",arr2);
let arr3 = arrMerge(newArr1, newArr2, "code");
arr3 打印输出结果如下:
6. JS 数组对象根据某一相同 key 合并成新的数组
需求是将具有相同 “school” 的对象合并为新的数组
例子:
# 原始数据
let arr = [
{ name: '小明',age: 20,school: '清华' },
{ name: '小红',age: 21,school: '清华' },
{ name: '小白',age: 18,school: '北大' },
{ name: '小黄',age: 19,school: '北大' },
{ name: '小浪',age: 21,school: '哈佛' },
]
# 期望数据
let data = [
{
school: "清华",
children: [
{ name: "小明", age: 20, school: "清华" },
{ name: "小红", age: 21, school: "清华" },
]
},
{
school: "北大",
children: [
{ name: "小白", age: 18, school: "北大" },
{ name: "小黄", age: 19, school: "北大" },
]
},
{
school: "哈佛",
children: [
{ name: "小浪", age: 21, school: "哈佛" },
]
},
]
实现代码如下:
function handlerDatas(arr){
let obj = {};
arr.forEach((item, index) => {
let { school } = item;
if (!obj[school]) {
obj[school] = {
school,
children: []
}
}
obj[school].children.push(item);
});
let data = Object.values(obj); // 最终输出
return data
}
7. 扁平数组转 tree 结构
const flatArr = [
{ id: '01', parentId: 0, name: '节点1' },
{ id: '011', parentId: '01', name: '节点1-1' },
{ id: '0111', parentId: '011', name: '节点1-1-1' },
{ id: '02', parentId: 0, name: '节点2' },
{ id: '022', parentId: '02', name: '节点2-2' },
{ id: '023', parentId: '02', name: '节点2-3' },
{ id: '0222', parentId: '022', name: '节点2-2-2' },
{ id: '03', parentId: 0, name: '节点3' },
]
function getData (arr) {
// 利用两层filter实现
let data = arr.filter(item => {
item.children = arr.filter(e => {
return item.id === e.parentId
})
return !item.parentId
})
return data
}
const res = getData(flatArr)
console.log('res', res)
打印结果如下: