一、Set和Map
Set是一个不能有重复元素的集合。
Set中的所有的数据都不是按索引排列的。
因为没有索引,遍历时不能使用for和for in,只能使用for of、forEach...
- Set的方法实现
//新建Set
let set = new Set([1, 2, 3, 4, 5])
console.log(set)//Set(5) {1, 2, 3, 4, 5}
//添加元素
set.add(10);
console.log(set)//Set(6) {1, 2, 3, 4, 5,10}
//删除元素
set.delete(5);
console.log(set)//Set(6) {1, 2, 3, 4,10}
//判断此元素是否是该Set的成员
console.log(set.has(5))//false
console.log(set.has(10))//true
//清除所有元素
set.clear();
console.log(set)//Set(0) {}
- Set的遍历
//使用forEach
let set = new Set([1, 2, 10, 4, 5])
set.forEach(value=>console.log(value))//1 2 10 4 5
//使用for of
for(var value of set){
console.log(value)//1 2 10 4 5
}
- Set的应用 — 数组去重
let arr=[1,1,2,2,4,4,3,0]
let set = new Set(arr)
console.log(set)//Set(5) {1, 2, 4, 3, 0}
Map用键值对来存储数据,有长度
Map中key和value可以是任何类型
- Map的方法实现
//创建Map
var map = new Map()
//设置Map值
map.set("name", "大南瓜")
map.set("age", "18")
map.set("color", "橙色")
console.log(map)//Map(3) {"name" => "大南瓜", "age" => "18", "color" => "橙色"}
//获取属性名对应的属性值
console.log(map.get("name"))//大南瓜
//删除属性
map.delete("age");
console.log(map)//Map(2) {"name" => "大南瓜", "color" => "橙色"}
//判断是否存在该属性
console.log(map.has("name"));//true
console.log(map.has("age"));//false 因为刚刚已经删除,所以不存在
//判断长度(数据个数)
console.log(map.size)//2
//清除所有数据
map.clear()
console.log(map)//Map(0) {}
- Map的遍历
//创建Map
var maps = new Map()
//设置Map值
maps.set("name", "大南瓜")
maps.set("age", "18")
maps.set("color", "橙色")
// 对象的遍历
for (let obj of maps) {
console.log(obj);
/* (2) ["name", "大南瓜"]
(2) ["age", "18"]
(2) ["color", "橙色"] */
}
//属性名的遍历
for (let key of maps.keys()) {
console.log(key);//name age color
}
//属性值的遍历
for (let value of maps.values()) {
console.log(value);//大南瓜 18 橙色
}
//返回所有成员的遍历器
for (let item of maps.entries()) {
console.log(item);//和对象的遍历结果一样
}
//forEach遍历
maps.forEach((v, k, list) => { console.log(v, k, list) })
/* 大南瓜 name > Map(3) { "name" => "大南瓜", "age" => "18", "color" => "橙色" }
18 age > Map(3) { "name" => "大南瓜", "age" => "18", "color" => "橙色" }
41 橙色 > color Map(3) { "name" => "大南瓜", "age" => "18", "color" => "橙色" } */
二、Promise
Promise对象是一个构造函数,用来生成Promise实例
- 基本结构——以图片加载函数为例
function getImgs(src) {
return new Promise(function (resolve, reject) {
// 参数resolve、reject分别表示异步操作执行成功后和失败后的回调函数
let img = new Image();
img.src = src;
img.onload = function (e) {
resolve(img);//resolve将Promise的状态置为fullfiled
};
img.onerror = function (e) {
reject("错误");//reject将Promise的状态置为rejected
}
});
}
- then方法,用以访问当前值、最终的返回值以及失败的原因。多个then方法连用将会形成链式异步
// 接受两个函数参数
getImgs("img01.png").then(function (img) {
console.log(img);//对应于状态变化到Resolved时的函数调用
}), function (error) {
console.log(error);//对应于状态变化到Rejected时的函数调用
}
- catch方法,就相当于.then(undefined, onRejected)
getImgs("img01.png").then(function (img) {
console.log(img);
}).catch(function (error) {
console.log(error);//带一个参数,为失败时的回调
})
- all方法,用于全部异步完成统一执行
Promise.all([getImgs("1.png"), getImgs("2.png"), getImgs("3.png")])
.then(function (imgArr) {
//根据异步调用的先后顺序获取到一个数组,数组中就是所有传入的参数
for (let i = 0; i < imgArr.length; i++) {
document.body.appendChild(imgArr[i]);
}
})
- race方法,用于同时执行多个异步,哪个先完成就处理这个先完成的
Promise.race([getImgs("1.png"), getImgs("2.png"), getImgs("3.png")])
.then(function (img) {
//只返回最先加载的数据
document.body.appendChild(img);
})
三、async和await
async 函数返回一个 Promise 对象,里面的return相当于promise中的resolve,await 下面的代码属于微任务
//基本写法
async function allLoad() {
var arr = [];
for (var i = 10; i < 18; i++) {
// 阻塞式异步
await loadImage("01.jpg").then(function (img) {
arr.push(img);
});
}
return arr;
}
四、异步加载案例
异步分为宏任务和微任务,前者将当前任务放在下一个任务列最顶部,有setTimeout setInterval,后者将当前任务放在当前任务列的最底部,有Promise async await
//以下注释中的数字标示为执行顺序
async function async1() {
console.log('async1 start');//2 同步
await async2();
//await 下面的代码属于微任务
console.log('async1 end')//5 当前任务列1
}
async function async2() {
console.log('async2')//3 同步
}
console.log('script start');//1 同步
setTimeout(function () {
console.log('setTimeout')//7 下一个任务列
}, 0);
async1();
new Promise(function (resolve) {
console.log('promise1');//4 同步
resolve()
}).then(function () {
console.log('promise2')//6 当前任务列2
});