一 解构赋值
解构赋值
解构指的是把一个数据结构拆开
赋值则是把其赋值给另外一个一摸一样的数据结构
三类
1.数组的解构赋值
2.对象的解构赋值
3.字符串的解构赋值
(一) 数组的解构赋值
数组解构的核心是 结构 保持一致
var names = ['小强', '张三', '李四']
var [name1, name2, name3] = names
PS:不完全解构
let arr2 = [1, 2] let [num1] = arr2
<script>
// 数组解构的核心是 结构保持一致
var names = ['小强', '张三', '李四']
// 需求:想让这里面的名字拿出来 分别命名为name1 name2 name3
// 之前写法:var name1=names[0]
// 可以使用解构赋值来实现 注意保持结构一模一样
var [name1, name2, name3] = names
console.log(name1);//小强
console.log(name2);//张三
console.log(name3);//李四
</script>
<script>
var arr1 = [
{userName: '旺财', age: 18 },
[99, 88],
111
]
// 需求:把数据拿出来 userName age score id
var [{ userName, age }, score, id] = arr1
console.log(userName);//旺财
console.log(age);//18
console.log(score);//[99, 88]
console.log(id);//111
</script>
<script>
let arr2 = [1, 2]
// 不完全解构(即不完全拿到数据)
let [num1] = arr2
console.log(num1);//1
let arr3 = [1]
let [num2, num3] = arr3
console.log(num2);//1
console.log(num3);//und
</script>
(二) 对象的解构赋值
对象解构的核心是 属性名 保持一致
let obj = { username: '旺财', age: 18 }
当对象的属性名和属性值一样时 可以省略为一个
let { username: username, age: age } = obj
let { username, age } = obj
PS:
当对象解构赋值时,不能修改里面的value值
但是可以在解构赋值的过程中新添加一个值
let obj2 = { username1: '旺财', age1: 18, sex1: '女' };
let { username1, age1, sex1 = '男' } = obj2
<script>
let obj3 = {
arr: [
'hello',
{ msg: 'es6' }
]
}
let {
arr: [
str1,
{ msg: str2 }
]
} = obj3;
console.log(str1, str2);//hello es6
</script>
<script>
let obj4 = {
f1: function () {
console.log(1);
},
f2: function () {
console.log(2);
}
}
// 对象的不完全解构
let { f1 } = obj4;
f1()// 1
f2()// f2 is not defined
</script>
(三) 字符串的解构赋值
字符串的解构赋值 某种意义上 可以参照数组
var str = 'h e'
// 左边是[]罩起来不是''
let [a, b, c] = str
console.log(a);//h
console.log(f);//
console.log(g);//E
(四) 函数形参的解构赋值
function bar([x, y]) {
console.log(x);
console.log(y);
}
// [x, y]=[1, 2]
bar([1, 2])
function fn({ x, y, z = 3 }) {
console.log(x);
console.log(y);
console.log(z);
}
// { x, y, z = 3 }={ x: 1, y: 2}
fn({ x: 1, y: 2 })
二 展开运算符和rest运算符
(一) 展开运算符
展开运算符 又叫 拓展运算符 形式:...
可以把一个数组转换为用逗号分开的序列
// 需求: 将两个数组进行合并
var arr1 = [1, 2, 3]
var arr2 = [4, 5, 6]
var arr3 = [...arr1, ...arr2]
console.log(arr3);//[1, 2, 3, 4, 5, 6]
// 需求:找最大值
var arr4 = [2, 4, 6, 57, 3, 2, 6, 78, 54, 3, 2];
console.log(Math.max(...arr4));//78
(二) rest运算符
rest运算符 形式:...
// 当前你要定义一个函数 但是这个函数的参数不确定
function fn(...args) {
console.log(args);
}
fn([1, 2], 3)
// 解构赋值+res运算符... 只能获取前几个值
var arr1 = [1, 2, 3, 4]
//A rest element must be last in a destructuring pattern
// let [a, ...b, c] = arr1
let [a, b, ...c] = arr1
console.log(a);//1
console.log(b);//2
console.log(...c);//3 4
console.log(c);//[3 4]
(三)展开和rest运算符区别
当...出现在赋值运算符右侧/作为函数实参时:拓展(展开)运算符
var arr3 = [...arr1, ...arr2]
Math.max(...arr4)
当...出现在赋值运算符左侧/作为函数形参时:rest运算符
let [a, b, ...c] = arr1
function fn(...args) {
console.log(args);
}
PS: args-- arguments 参数
三 浅拷贝对象Object.assign()
Object.assign() --浅拷贝
浅拷贝--拷贝了地址,共用一个堆空间,所以一个改变其他随之改变
作用:将源对象的所有可枚举的属性 复制到目标对象
需要2个参数
第一个参数是目标参数 -- obj3
后续的参数都是源对象 -- obj1,obj2
PS:
Object.assign VS cloneNode
浅克隆-cloneNode() 仅克隆该节点,不克隆其中后代节点
深克隆-cloneNode(true) 将节点的后代节点也克隆
var obj1 = {
name: 'zhangsan',
address: '郑州',
hobby: '写代码'
}
var obj2 = {
age: 18
}
Object.assign(obj3, obj1, obj2)
console.log(obj3);
// Object.assign -- 浅拷贝
// 深拷贝(开辟了一个新的堆地址,各自独立拥有堆空间)
// 浅拷贝(拷贝了地址,共用一个堆空间)
var obj7 = {
address: {
city: "郑州"
}
}
var obj8 = {}
Object.assign(obj8, obj7)
// 改的是obj8属性但是obj7随之改变--因为浅拷贝,指向同一地址
obj8.address.city = "上海"
console.log(obj7);//上海
四 Object.defineProperty()
(一) 给对象添加属性并添加对应配置项
var obj = {}
//
Object.defineProperty(obj, 'age', {
value: 18,
// 是否可被枚举
enumerable : false //默认值是false 不可被枚举
})
console.log(obj);
// 不可被枚举 for in也循环不到
for (let key in obj) {
console.log(obj[key]);
}
// 不可被枚举 不能被复制
let obj6 = {}
Object.assign(obj6, obj)
console.log(obj6);
(二) 监听对象的多个属性 循环遍历
let obj1 = {
name: '张三',
age: 18,
money: 5000
}
for (let key in obj1) {
Object.defineProperty(obj1, key, {
set(value) {
// value -- 被修改的新值
console.log('set被调用了');
console.log('set的新值:' + value);
},
get() {
console.log('get被调用了');
}
})
}
console.log(obj1.name);//get被调用了
obj1.money = 3000;//set被调用了 set的新值:3000
五 Proxy代理
proxy --代理
代理模式 --程序设计的一种设计模式 监听一个对象上的属性
Proxy用于修改某些操作的默认行为, 可以理解在目标对象之前,设置了一个拦截 ,如果外界去访问对象(数据)的时候,都需要通过这层拦截,就可以对外界的访问进行过滤和改写
(一) Proxy代理相关概念
1.Proxy作用
1.屏蔽原始数据 2.保障原始数据安全
2.Proxy构造器中参数
第一个参数 代理对象 第二个参数 配置项
(二) Proxy捕获器
let obj = {
name: '李四',
age: 18
}
let objProxy = new Proxy(obj, {
// 监听获取动作
get: function (target, key) {
console.log('get被执行了');
},
// 监听设置动作
set: function (target, key, newValue) {
console.log('set被执行了');
console.log(newValue);
},
// 监听in动作
has: function (target, key) {
console.log('in捕获器');
return key in target
},
// 监听删除动作
deleteProperty: function (target, key) {
console.log('delete触发了');
}
})
// in 判断属性有没有在这个对象上 或者说 对象上有没有此属性
console.log('name' in objProxy);//true delete objProxy.name//不影响obj
console.log(obj);
六 class
(一)class概念及使用
class是一个语法糖,就是你相同代码的功能可以简写
箭头函数也是语法糖
class Student {
// 如果想要给这个类的对象添加属性的时候
constructor(name, age) {
// 挂载在对象身上的私有属性
this.name = name
this.age = age
// constructor的作用
// 1.创建一个对象
// 2.将Person的prototype赋值给创建出来的实例化对象 p.__proto__=Person.prototype
// 3.让this指向对象p--让this指向p
// 4.执行内部代码
}
// 挂载在原型对象上 公有属性
say() {
console.log('say...');
}
}
// class继承extends
class Mointor extends Student {
constructor(name, age, id) {
super(name, age)
this.id = id
}
}
let m = new Mointor("张三", 18, 1)
console.log(m);
(二)class设置器和访问器
class Student {
constructor(address, age) {
this._address = address
this.age = age
}
// 访问器
get address() {
console.log('get被调用了');
return this._address
}
// 设置器
set address(value) {
console.log('set被调用了');
this._address = value
// console.log('设置值:' + value);
}
}
let stu = new Student('郑州', 18)
console.log(stu._address);//加上下划线相当于正常的访问属性
console.log(stu.address);//不加下划线 相当于通过get set去访问的
// stu._address = '上海'
stu.address = '上海';
console.log(stu);
(三)class静态属性|方法 static
静态属性|方法 static
- 如果在一个方法前,加上static关键字,就表示该方法不会被实例继承
- 只能通过构造器去访问 不能通过实例之后的对象来访问
且静态方法里的this只能访问静态属性
<script>
class Person {
// 静态属性/方法
static say() {
console.log(11);
}
}
// 静态属性 只能通过构造器去访问 不能通过实例之后的对象来访问
Person.say()
// 注意:不能通过实例之后的对象变量来访问
let p = new Person()
p.say() //say is not a function
</script>
<script>
// 静态方法里的this只能访问静态属性
class Person {
// 公共属性
static names = "张三"//静态属性
age = 18
static show() {
console.log(this.names);//张三
console.log(this.age);//und
console.log(Person === this);//true
}
}
Person.show()//张三 und
七 Symbol()
问题:协同开发 对象中属性名冲突
问题本质原因:属性名的不唯一性
解决方法:Symbol()
属性名可重复 只是书写方式不同:属性名需加[]
let mySymbol1 = Symbol('mySymbol1')
mySymbol1: 'mySymbol1', [mySymbol1]: '第一种方式'
调用方式不同:一个对象打点,一个对象[] console.log(obj.mySymbol1); console.log(obj[mySymbol1]);
(一) Symbol()特点
- 这种数据由Symbol函数产生 独一无二
- 可保证对象中属性名是唯一的
- 可传递字符串作为参数
let s3 = Symbol('s')
let s4 = Symbol('s')
console.log(s3);//Symbol(s)
console.log(s3 == s4);//false
(二) 通过Symbol()避免属性名冲突-三种方式
let obj = {}
// 第一种方式[mySymbol1]: '第一种方式'
let mySymbol1 = Symbol('mySymbol1')
obj = {
mySymbol1 : 'mySymbol1' ,
[mySymbol1]: '第一种方式'
}
// 这样属性名就可重复,只是调用方式不同
console . log (obj. mySymbol1 );
console . log (obj[mySymbol1]);
// 第二种方式 obj[mySymbol2] = '第二种方式';
let mySymbol2 = Symbol('mySymbol2')
obj[mySymbol2] = '第二种方式';
console.log(obj[mySymbol2]);
// 第三种方式 Object.defineProperty()
let mySymbol3 = Symbol('mySymbol3')
Object.defineProperty(obj, mySymbol3, {
value: '第三种方式',
enumerable:true
})
console.log(obj[mySymbol3]);
console.log(obj);
八 Set和Map
Es6中 新增了两种结构 set map weakset weakmap
应用场景:
Map:适用于需要将键映射到值的情况,例如管理用户权限、存储对象之间的关联关系等
Set:适用于需要存储一组唯一值的情况,例如去重数组中的重复项、跟踪一组唯一的项目等
set和数组结构相似 但是set可以去重,set里没有重复的元素
(一) Set
1.Set操作方法
1.add(value) 返回Set结构本身
2.delete(value) 返回布尔值-删除是否成功
3.clear() 清除所有成员 返回值undefined
4.has(value) 返回布尔值-参数否是Set的成员
PS:Set实例化对象添加重复元素无效
let s = new Set()
s.add(1)
s.add(1)//添加重复元素无效
console.log(s.add(2));//Set(2) {1, 2}
console.log(s.has(2));//true
console.log(s.delete(2));//true
s.clear();
console.log(s);//Set(0) {size: 0}
2.Set转Array--Array.from()
let s = new Set()
s.add(1)
s.add(2)
s.add(3)
console.log(s);
//通过Array.from()方法将Set转为Array
let arr = Array.from(s)
console.log(arr);
3.WeakSet-成员类型只能是对象类型
WeakSet 和Set类似的另一个数据结构 也是内部成员不能重复
1.WeakSet成员类型只能是对象类型 不能放其他类型
2.WeakSet不能遍历 如果遍历了 获取其中的元素 那么里面的对象无法被正常销毁
let weakset = new WeakSet()
let obj1 = {
name: '1'
}
let obj2 = {
name: '2'
}
weakset.add(obj1)
weakset.add(obj2)
// weakset.add(1)//Invalid value used in weak set
console.log(weakset);
(二) Map
1.Map操作方法
set(key,value)
get(key)
has(key)
delete(key)
clear()
let map = new Map()
let obj = {
city: "郑州"
}
map.set(obj, '大玉米')
console.log(map.set('开封', '清明上河园'));//Map(2) {{…} => '大玉米', '开封' => '清明上河园'}
console.log(map.has(obj));//true
console.log(map.get(obj));//大玉米
console.log(map.delete(obj));//true
console.log(map); //Map(1) {'开封' => '清明上河园'}
2.WeakMap-用key只能是对象类型
1.WeakMap 用对象作为key 不能使用基本数据类型作为key
2.WeakMap不能遍历
九 Promise
(一) 前置知识--JS代码执行顺序
1.相关概念
异步任务 宏任务和微任务 特点:先微后宏
执行优先顺序:同步代码-->异步代码(微任务->宏任务)
-
同步任务
- 按照顺序执行,执行完一个再执行下一个
-
异步任务(宏任务和微任务)
- 微任务:Promise.then、Promise、async/await
- 宏任务:定时器(setTimeout setInterval)、事件监听、Ajax、DOM事件
- 在后台执行,等到异步任务完成后再执行回调结果。
- 异步任务执行顺序不确定,因为在后台执行
2.JS代码的执行顺序
- 从代码段开始执行
- 如果遇到一个宏任务,会把这个任务放到一个宏任务队列,如果遇到一个微任务,就把这个微任务放到微任务任务中。
- 当同步代码执行完毕后,先去清空微任务队列。
- 当微任务队列清空完毕后,从宏任务队列中取出一个宏任务,去执行,在执行过程中,你的宏任务中可能还有同步代码或宏任务或微任务,重复上面的步骤,执行完一个宏任务,肯定要清空微任务队列。
PS:
1.async内遇到await先执行await,其中有异步代码的话--阻塞async后面代码执行,但不阻塞async外代码继续执行
2.promise执行resolve()或者reject()改变状态时才会把其then方法放进微任务队列
3.Event Loop
(二) 旧解决异步问题方式-回调函数
异步问题:js单线程执行,如何实现异步
之前的方式:回调函数
缺点:过多函数嵌套导致出现”回调地狱”
// 最早解决异步问题:靠回调函数
// 1.设计这样的一个函数
function execCode(counter, successCallback, failureCallback) {
// 异步任务
setTimeout(() => {
if (counter > 0) { // counter可以计算的情况
let total = 0
for (let i = 0; i < counter; i++) {
total += i
}
// 在某一个时刻只需要回调传入的函数
successCallback(total)
} else { // 失败情况, counter有问题
failureCallback(`${counter}值有问题`)
}
}, 3000)
}
// 2.ES5之前,处理异步的代码都是这样封装
execCode(100, (value) => {
console.log("本次执行成功了:", value)
}, (err) => {
console.log("本次执行失败了:", err)
});
(三) Promise相关概念
1.promise概念及作用
概念:promise是解决异步编程的一种解决方案,合理且强大 可以替代传统的解决方案-回调函数
好处:异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
作用:主要是为了解决异步的问题 让异步代码先执行
PS:promise可以解决异步的问题,但不能说promise本身是异步的
2.Promise对象特点
- 对象的状态不受外界影响
- 一旦状态改变不会二次更改
3.Promise对象的三种状态--PromiseState属性
- 等待状态:pending 默认创建出来promise出于等待状态
- 成功状态:fulfilled 当调用resolve函数时,promise从等待态变为成功态
- 失败状态:rejected 当调用reject函数时,promise从等待态变为失败态
PS:
对一个Promise对象来说 成功或失败后 不能再次改变其状态
即只能从等待状态转为成功状态 / 从等待状态转为失败状态
// 1.等待态 pending 默认
let p1 = new Promise((resolve, reject) => {
})
console.log(p1);
// 2.成功态 fulfilled 调用resolve()
let p2 = new Promise((resolve, reject) => {
resolve('resolve')
})
console.log(p2);
// 3.失败态 rejected 调用reject()
let p3 = new Promise((resolve, reject) => {
reject('reject')
})
console.log(p2);
// 注意事项:
// 对一个Promise对象来说 成功或失败后 不能再次改变其状态
// 即只能从等待状态转为成功状态 / 从等待状态转为失败状态
let p4 = new Promise((resolve, reject) => {
resolve('resolve')
reject('reject')//无效
})
console.log(p4);//状态仍为fulfilled成功状态
4.Promise对象的三种终值--PromiseResult属性
- pending --终值 undefined
- fulfilled --终值 成功的结果
- rejected --终值 失败的原因
(四) Promise的then方法
1.每个promise对象都有then方法
- then的作用:then可以处理promise对象成功或失败之后的事情
- then的2个参数:分别对应成功后的回调和失败后的回调
let p1 = new Promise((resolve, reject) => {
resolve('成功')
})
// 传递一个参数--指的是成功的结果 PromiseResult
p1.then((result) => {
console.log(result);
})
let p2 = new Promise((resolve, reject) => {
reject('失败')
})
// 传递两个参数--一成功的结果 一失败的结果 PromiseResult
p2.then((result) => {
console.log(result);
}, (error) => {
console.log(error);
})
2.then的返回值
then的返回值是一个新的promise对象
- 返回成功态的promsie:上一个then返回一个普通的值(包含und)
- 返回失败态的promise对象:上一块代码报错
- 返回新的promise对象:then的返回值是一个新的promise对象
- 返回成功态的promsie:上一个then返回一个普通的值(包含und)
let p1 = new Promise((resolve, reject) => {
// reject('失败')
resolve('成功')
})
// 上一个then返回一个普通的值(包含und) 新的promise是成功的promsie
let p2 = p1.then((result) => {
console.log(result);//成功
}, (error) => {
console.log(error);
})
console.log(p1);
console.log(p2);
- 返回失败态的promise对象:上一块代码报错
let p1 = new Promise((resolve, reject) => {
// reject('失败')
resolve('成功')
})
let p2 = p1.then((result) => {
console.log(result);//成功
throw new Error('出了小错')
}, (error) => {
console.log(error);//失败
throw new Error('出了小错')
})
console.log(p1);
console.log(p2);
- 返回新的promise对象:then的返回值是一个新的promise对象
let a = new Promise((resolve, reject) => {
resolve('成功')
// reject('失败')
})
let a1 = a.then(result => {
// 在成功态里面返回了一个失败态的promise
console.log(result);
let a3 = new Promise((resolve, reject) => {
reject('失败')
})
return a3
}, error => {
console.log(error);
// 在失败态里面返回了一个成功态的promise
let a4 = new Promise((resolve, reject) => {
resolve('成功')
})
return a4
})
console.log(a1);
3.then的顺延
- 1.1少写一个参数
- 1.2不写参数
- catch会把then失败的情况单独拎出来
- finally -- 最终都会走这个finally
- 少写一个|不写参数
// 当你promise对象的then中没有成功或者失败的处理 那么会顺延到下一个promise对象中做处理
let p2 = new Promise((resolve, reject) => {
reject('失败')
})
p2.then(result => {
console.log(1);
}).then(result => {
console.log(3);
}, errer => {
console.log(4);
})
// 1.2不写参数
let p3 = new Promise((resolve, reject) => {
resolve('成功')
})
p3.then().then(result => {
console.log(3);
}, error => {
console.log(4);
})
- catch 把then失败的情况单独拎出来
let p4 = new Promise((resolve, reject) => {
reject('失败')
})
p4.then(result => {
console.log('处理成功');
}).catch(error => {
console.log('处理失败');
})
- finally 最终都会走这个finally
let p5 = new Promise((resolve, reject) => {
reject('失败')
})
p5.then(result => {
console.log('处理成功');
}).catch(error => {
console.log('处理失败');
}).then(result => {
// 前面return的值,result拿到的是上一个promise的终值
console.log(result);//und
}).finally(() => {
console.log('最终');
})
(五) 利用Promise解决异步问题
function fn(num) {
// 同步代码
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log('异步1');
if (num >= 50) {
resolve('v我50')
} else {
reject('v你50')
}
}, 1000)
console.log('同步1');
})
}
// .then函数内 异步代码
fn(49).then((result) => {
console.log(result);
}, (error) => {
console.log('异步2');
console.log(error);
})//v你50
console.log('同步2');
//同步1 同步2 异步1 异步2 v你50
(六) Promise的resolve的实参
1.普通参数
resolve('成功')
2.参数是一promise对象
let p2 = new Promise((resolve, reject) => {
reject('失败1')
})
resolve(p2)
3.是一个thenable (一不完整的promise对象)
thenable:就是一个对象中有一个then函数
resolve({
//then: function(resolve, reject) {}
then(resolve, reject) {
reject('失败2')
}
})
(七) Promise的静态方法
1、2. resolve、reject
// 最常规的两个静态方法 1.resolve 2.reject
// 可以直接创建一个成功或者失败的promise对象
let p1 = Promise.resolve('成功')
console.log(p1);
let p2 = Promise.reject('失败')
console.log(p2);
3.all
// 3.all
// 表示所有的promise都成功后 得到所有promise成功的结果
// 如果有一个失败 则直接得到最先失败的promise的结果
// all参数传递的是一个数组的格式
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p3成功')
reject('p3失败')
}, 3000)
})
let p4 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p4成功')
}, 2000)
})
let p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p5成功')
}, 4000)
})
Promise.all([p3, p4, p5]).then(result => {
console.log(result);
}).catch(error => {
console.log('走了catch');
console.log(error);
})
//['p3成功', 'p4成功', 'p5成功']
4.any
// 4.any
// 等待最先成功的promise 或者 得到所有Promise都失败(All promises were rejected)
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p3成功')
reject('p3失败')
}, 3000)
})
let p4 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p4成功')
reject('p4失败')
}, 2000)
})
let p5 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p5成功')
reject('p5失败')
}, 4000)
})
Promise.any([p4, p5, p3]).then(result => {
console.log('走了then');
console.log(result);
}).catch(error => {
console.log('走了catch');
console.log(error);//All promises were rejected
})
5.allSettled
// 5. allSettled
// 表示所有的promise的结果 不管成功还是失败 最后都会走成功态方法result=>{}
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3成功')
}, 3000)
})
let p4 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p4成功')
reject('p3失败')
}, 2000)
})
let p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p5成功')
}, 4000)
})
Promise.allSettled([p4, p5, p3]).then(result => {
console.log('走了then');
console.log(result);
}).catch(error => {
console.log('走了catch');
console.log(error);
})
6.race
// 6. race
// 等待最先拿到状态的promise结果 不管成功还是失败
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3成功')
// reject('p3失败')
}, 3000)
})
let p4 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p4成功')
reject('p4失败')
}, 2000)
})
let p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p5成功')
}, 4000)
})
Promise.race([p5, p4, p3]).then(result => {
console.log('走了then');
console.log(result);
}).catch(error => {
console.log('走了catch');
console.log(error);
})
十 async+await(≈Promise)
-
async关键字(修饰符) 是异步的简写 用于声明一个异步函数
- async用于声明一个function是异步的
- 函数用async修饰后,变成异步函数,会返回一个promise对象
-
await关键字 async wait的简写
- await 不能单独使用,必须在async的修饰下使用
- await 用于等待一个异步方法执行完成
个人理解:
-
async与new Promise()功能类似
- 返回promise对象,不加await正常执行
-
await与promise.then()方法类似
- async内遇到await时,若await的函数中有异步代码则不再向下执行-async内部阻塞,但是async外面的同步代码仍正常运行
(一) async
1.async的几种写法
具名函数、匿名函数、箭头函数、使用class声明类
// 具名函数的写法
async function fn() {
console.log(123);
}
console.log(fn());
// 匿名函数的写法
let gn = async function () {
}
console.log(gn());
// 箭头函数的写法
let tn = async () => { }
console.log(tn());
// 使用class声明类
class Person {
async eat() {
}
}
let p = new Person()
console.log(p.eat());
2.async函数return返回值-对应promise状态
- 返回是一个普通值/不返回(即und) 那么整个promise状态是成功态
- 返回的是一个promise对象 内部的promise对象的最终状态会影响到外部
- 返回的是一个thenable对象 内部的thenable对象的最终状态会影响到外部
return {
then(resolve, reject) {
reject('失败')
}
}
- 代码中有异常,抛出错误(代码运行并不终止) 那么整个promise就是一个失败态
async function foo() {
// 1.返回是一个普通值 状态是成功态
return 123
// 2.返回的是一个promise对象 内部的promise对象的最终状态会影响到外部
// return new Promise((resolve, reject) => {
// // resolve('成功')
// reject('失败')
// })
// 3.返回的是一个thenable对象 内部的thenable对象的最终状态会影响到外部
// return {
// then(resolve, reject) {
// reject('失败')
// }
// }
// 4.代码中有异常,抛出错误,那么整个promise就是一个失败态
// console.log(a);
}
console.log(foo());
foo().then(result => {
console.log(result);
}, err => {
console.log(err);
})
console.log('hhhh');
// Promise
// hhhh
// 123
(二) await
await 不能单独使用,必须在async的修饰下使用
PS:
- await等待的是一个成功的promise的结果,拿到成功的结果,才会执行async内的后续代码否则中断不再执行
- await执行过程中遇到异步代码会阻塞不再向下执行async内部代码,但同时不影响async外部剩下同步代码的执行
// await等待的是一个成功的promise的结果,拿到成功的结果,才会执行async内的后续代码
// async+await可替换new Promise()+then
async function foo() {
await new Promise((resolve, reject) => {
// resolve('成功')
reject('失败')//微任务
console.log(1);
})
console.log(111);//未执行
}
foo()//1
console.log('async外的同步代码');//async外的同步代码
十一 ES6+中的其他方法
(一) Object.keys和Object.values和Object.entries
通过 Object.keys 获取一个对象所有的key
通过 Object.values 来获取所有的value值
通过 Object.entries -- 对对象、数组/字符串的操作
对对象:获取所有的[key,value]值
对数组/字符串:获取所有的索引+数组/字符串对应项
let obj = {
name: 'wc',
age: 18,
height: 180,
address: 'zz'
}
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));
console.log(Object.entries(['zs', 'ls']));
console.log(Object.entries("hi"));
(二) String的padStart()|padStart()
String Padding 某些字符串进行前后的填充,来实现某种格式化效果
应用场景:比如需要对身份证、银行卡的前面位数进行隐藏
- padStart() 用于头部补全
- padEnd() 用于尾部补全
let cardNumber = '410233043254032403';
// 截取前14位
let sliceNumber = cardNumber.slice(0, 14)
// 总长度cardNumber.length,减去sliceNumber.length剩余位数用'*'替换
cardNumber = sliceNumber.padEnd(cardNumber.length, '*')
console.log(cardNumber);//41023304325403****
(三)flat() 按指定的深度递归遍历数组
// 三维数组
let nums = [ 10, 20, [111, 222], [333, 444], [[123, 321, ["a", "b"]], [456, 654]]
]
// flat(0)深度为0
let numarr = nums.flat(0)
console.log(numarr);
// nums.flat()与nums.flat(1)都是深度为1
numarr = nums.flat(1)
console.log(numarr);
numarr = nums.flat(2)
console.log(numarr);
//深度Infinity-无穷大
numarr = nums.flat(Infinity)
console.log(numarr);
(四)||和??
-
|| 逻辑或运算符
- 如果第一操作值为假值(null、undefined、false、空字符串、0、NaN), 那么就会返回第二个值。如果第一个值为真值,返回第一个值。
- 一般用在处理默认值或者条件运算
-
?? 空值合并操作符
- 如果第一个操作数是空值(例如 null 或 undefined),那么它就会返回第二个操作数的值。反之返回第一个值
- 一般用于简化代码进行空值合
-
||逻辑或运算符 VS ??空值合并操作符
- 值判断范围不同: || 判断是否为假值 , 而 ?? 主要针对null undefined
- 用途稍有不同:|| 是逻辑运算符偏向逻辑处理, ??主要为了简化代码
let info1 = 0
info1 = info1 || '默认值'
console.log(info1);//默认值
let info2 = 0
info2 = info2 ?? '默认值'
console.log(info2);//0
十二 箭头函数
(一)箭头函数实例
var fn = () => {
// {} 函数体
// () 形参列表
}
// 当一个参数的时候 省略括号()
var f1 = i => { }
// 当函数体只有一句话的时候的时候 省略{}
var f1 = i => console.log(i);
// 当只有一个返回值的时候 return省略
var f3 = i => 10
// 当你返回的是一个对象 需要在函数体外部加上括号
var f4 = i => ({ a: 1 })
function Person(name) {
this.name = name;
}
// 注意:箭头函数内没有this
let Person = (name) => {
this.name = name;
}
let p = new Person()
(二)哪些地方不能使用箭头函数(涉及this指向问题)
1.不能作为构造器,因为不能new(用this赋值)
2.在ES6中声明class类里的constructor函数,不能使用箭头函数
3.给原型对象添加方法的时候 不要使用箭头函数
十三 声明变量 let|const
1.let声明的特点
1.let声明不会提升 (提升 但是没有初始化)
2.let声明的变量不会挂载在window上
3.let不能对变量重复声明
4.let会和{}形成块级作用域
2.const声明(常量)特点
1.不会提升 (提升 但是没有初始化)
2.和{}形成块级作用域
3.不能重复声明
4.不能挂载在window(Go)上
5.不能被改变
6.声明的时候必须赋值
(二) let形成暂时性死区
// 形成了暂时性死区
// 由于let提升但是未初始化 导致在一片区域内 不能按照作用域链向上寻找变量
// 这个区域叫暂时性死区
var a = 1
{
console.log(a);//Cannot access 'a' before initialization
let a = 2;//let声明提升但未初始化
}