reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,
接受四个参数:初始值,当前元素值,当前索引,调用 reduce 的数组。
1、initialValue 初始值
2、current 数组中当前被处理的元素
3、index 当前元素在数组中的索引
4、array 调用 reduce 的数组
项目运用实例:
接口获取两组数据,将id相同的合并,并且重复的不能覆盖,数据如下:
nameList:
[
{
name: "张三",
id: 1,
},
{
name: "张三",
id: 1,
},
{
name: "李四",
id: 2,
},
{
name: "王五",
id: 3,
},
],
ageList:
[
{
age:18,
id: 1,
},
{
age:20,
id: 2,
},
{
age:25,
height:180,
id: 3,
},
],
方法:(此处注意若要去重可用.find()去查找,返回第一个满足条件的目标id,然后直接Object.assign(target, cur)添加即可)
let list = ageList.reduce((pre, cur) => {
let target = pre.filter((ee) => ee.id == cur.id);
if (target) {
target.map((item, index) => {
Object.assign(item, cur);
});
} else {
pre.push(cur);
}
return pre;
},nameList);
最后得到的list结果:
[
{
name: "张三",
id: 1,
age:18
},
{
name: "张三",
id: 1,
age:18
},
{
name: "李四",
id: 2,
age:20
},
{
name: "王五",
id: 3,
age:25,
height:180,
},
],
平时做项目,涉及异步操作,使用最多的就是promise封装处理,以axios请求后台接口为例
get(url, params = {}) {
return new Promise((resolve, reject) => {
axios.defaults.headers.get['Content-Type'] = 'application/json;charset=UTF-8'; //设置请求头
if (window.globalConfig.isEncryption) {
// 判断加密,在全局配置文件设置了isEncryption(是否加密),这样的好处是线下调试和线上发布,可以根据自己的需求去更改isEncryption的true或者false,自行选择加密或者不加密传输
// 对原文"a=1&b=2"进行加密 encodeURIComponent
let _pm = Object.keys(params).map(key => {
return `${key}=${params[key]}`;
}).join('&');
let enc = encrypt(_pm); //此处的encrypt是引入的加密函数
params = {
data: enc
};
}
axios.get(url, {
params
})
.then(response => {
resolve(response.data);
}, err => { // 调用接口失败后的回调
reject(err);
});
});
}
调用get方法,多个请求.then()链式调用:
this.get("http://192.168.5.222:80/api/getlist1",params={.....})
.then(res=>{
//调用接口成功后的回调,此处需要注意,在成功的回调函数中,若出现错误,也会停止后面的执行,并执行err的回调
console.log("获取接口1的数据成功")
if(res&&res.code==200){
this.get("http://192.168.5.222:80/api/getlist2",params={.....})
.then(v=>{
console.log(v,"获取接口2的数据成功")
})
}
})
.catch(err=>{ // 调用接口失败后的错误信息打印
console.log(err)
})
归纳:
1.then和catch方法都是定义在原型对象上的,即promise.prototype.then()和promise.prototype.catch(),是作用于promise执行结果之后的回调函数
2.then方法接收两个参数,第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数,.catch相当于.then方法第一个参数为null,第二个参数为reject时,发生错误的回调。
3.then执行过程中抛出的错误,会被catch捕获,一般catch中打印错误报告,方便分析原因(实例:封装请求接口的函数,调用成功之后执行.then方法,若.then方法报错,比如某个值获取是undefined,在catch中可以打印error信息)
4.promise执行结果的状态是不可改变的,也就意味着,如果执行走了一条路,另外一个条路就不会走
5.promise内部代码错误,不会影响外部的代码运行,比如promise内部某个变量未定义报错,不会影响下面的代码正常运行。
6.then方法中的报错,总被后一个catch捕获,这也是为什么一般在使用的时候,都是.then(…).catch(…),如果catch在前面,就达不到捕获then抛出异常的目的了
经典案例:
var getJSON = function(url, param) {
var promise = new Promise(function(resolve, reject){
var request = require('ajax-request');
request({url:url, data: param}, function(err, res, body) {
if (!err && res.statusCode == 200) {
resolve(body);
} else {
reject(new Error(err));
}
});
});
return promise;
};
var url = "login.php";
getJSON(url, {id:1}).then(result => {
console.log(result);
return getJSON(url, {id:2})
}).then(result => {
console.log(result);
return getJSON(url, {id:3});
}).then(result => {
console.log(result);
}).catch(error => console.log(error));
async声明一个异步函数,await等待一个异步方法执行完成,一般await必须用在async函数中,等到一段代码执行完成,而不会造成阻塞
async function test1() {
console.log('start test1');
console.log(await test2());
console.log('end test1');
}
async function test2() {
console.log('test2');
return await 'return test2 value'
}
test1();
console.log('start async');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('end async');
数组扁平化即是二维或者多维数组转化为一维数组,项目的树形结构菜单运用比较多,方法总结:
1.es6的flat()方法
let arr= [1,2,[3,[4,5]]]
let res = arr.flat(Infinity)
console.log(res) // [1,2,3,4,5]
注:arr.flat()接收一个参数,
默认为1,代表拉平一个层次(二维数组扁平),
若传入2,则代表拉平两个层次,
若有未知层都需要扁平化,则传入Infinity关键字,
另外,若数组中有空位,则会跳过空位
2 拓展运算符
let arr= [1,2,[3,[4,5]]]
while(arr.some(Array.isArray)){
arr = [].concat(...arr)
}
3 forEach多层循环
var arr= [1,2,[3,[4,5]]]
function flatFn(arr,v=[]){
arr.forEach(item=>{
if(Array.isArray(item)){
flatFn(item,v)
}else{
v.push(item)
}
})
return v
}
let res = flatFn(arr)
console.log(res) // [1,2,3,4,5]
之前比较疑惑的,解构赋值到底是浅拷贝还是深拷贝,记以下实例,解构赋值是浅拷贝,只是针对一维数组或者对象来说,是深拷贝。
let a={
name:"xiaoming",
age:10,
height:180
}
let b = a
b.name = "daming"
b.age = 20
b.height = 160
console.log(a,b) // a和b均为adming,20,160
let a={
name:"xiaoming",
age:10,
height:180
}
let {name,age,height} = a
name = "daming"
age = 20
height = 160
console.log(a,name,age,height) //{name:"xiaoming",age:10,height:180},"daming",20,160
let a={
name:"xiaoming",
age:10,
height:180,
addr: { province: 'sichuan', city: 'chengdu' }
}
let {name,age,height,addr} = a
name = "daming"
age = 20
height = 160
addr.province = 'hunan'
addr.city = 'changsha'
console.log(a) //{name:"xiaoming",age:10,height:180,addr:{province: 'hunan', city: 'changsha'}}
console.log(name,age,height,addr) //"daming",age:20,height:160,addr:{province: 'hunan', city: 'changsha'}
结果来看,解构赋值改变了a对象内部addr这个对象的数据,还是浅拷贝
总结:解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,那它就是深拷贝;
如果是多维数组或对象,其本质就是对引用类型数据进行等号赋值,那它就是浅拷贝;
和链式操作符.类似,区别是遇到引用为null或者undefined的情况,不会报错,比如项目中后端返回的数据中,需要的某个字段没有,控制台会报错,代码就不会往下执行,但是用可选链操作符就会返回undefined而不是报错
let obj = {}
let res = obj.details.address
console.log(res) // 报错Cannot read properties of undefined (reading 'address')
let obj = {}
let res = obj.details?.address
console.log(res) // undefined
属于逻辑运算符,与||,&&相似,根据左右两边的结果,判断返回什么数据
区别:|| 左侧为false时返回右边,而??则是左侧为null或者undefined时返回右边
let a = 0 || 1
console.log(a) //返回1
let a = 0 ?? 1
console.log(a) //返回0
字符串中筛选出所有数字的案例
var str = 'sposd1234dapoc-12fw901ss0';
var arr = [];
var tmp = '';
for (var i = 0; i < str.length; i++) {
if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
tmp += str.charAt(i);
} else {
//三种情况,这里判断非空的情况
if (tmp) {
arr.push(tmp);
tmp = '';
}
}
}
//最后一位索引是数字,需额外判断
if (tmp) {
arr.push(tmp);
tmp = '';
}