老样子。复制上来的图片都没了,想看原版可以移步对应资源下载(资源刚上传,还在审核中)
 
(免费)菜狗学前端之ES6+笔记 https://download.csdn.net/download/m0_58355897/89135424
https://download.csdn.net/download/m0_58355897/89135424
 
一 解构赋值
 
|         解构赋值         解构指的是把一个数据结构拆开         赋值则是把其赋值给另外一个一摸一样的数据结构         三类         1.数组的解构赋值         2.对象的解构赋值         3.字符串的解构赋值 | 
 
(一) 数组的解构赋值
 
| 数组解构的核心是 结构保持一致 var names = ['小强', '张三', '李四'] var [name1, name2, name3] = names PS:不完全解构 let arr2 = [1, 2]let [num1] = arr2
 | 
 
 
| HTML<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 | 
 
 
| HTML<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 | 
 
(四) 函数形参的解构赋值
 
| JavaScriptfunction 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运算符
 
(一) 展开运算符
 
|         展开运算符 又叫 拓展运算符        形式:...         可以把一个数组转换为用逗号分开的序列 | 
 
 
| JavaScript// 需求: 将两个数组进行合并
 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运算符
 
 
 
| JavaScript// 当前你要定义一个函数 但是这个函数的参数不确定
 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)  将节点的后代节点也克隆 | 
 
 
| JavaScriptvar 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()
 
(一) 给对象添加属性并添加对应配置项
 
| JavaScriptvar 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);
 | 
 
(二) 监听对象的多个属性 循环遍历
 
| JavaScriptlet 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捕获器
 
| JavaScriptlet 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是一个语法糖,就是你相同代码的功能可以简写 箭头函数也是语法糖 | 
 
 
| JavaScriptclass 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设置器和访问器
 
| JavaScriptclass 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只能访问静态属性 | 
 
 
| HTML<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()特点 
 
 
 
 
| JavaScriptlet s3 = Symbol('s')
 let s4 = Symbol('s')
 console.log(s3);//Symbol(s)
 console.log(s3 == s4);//false
 | 
 
(二) 通过Symbol()避免属性名冲突-三种方式
 
| JavaScriptlet 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实例化对象添加重复元素无效
 
| JavaScriptlet 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()
 
| JavaScriptlet 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不能遍历 如果遍历了 获取其中的元素 那么里面的对象无法被正常销毁 | 
 
 
| JavaScriptlet 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()
 
| JavaScriptlet 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代码执行顺序
 
js代码执行顺序:同步代码-->异步代码(微任务->宏任务)
 
异步任务 宏任务和微任务 特点:先微后宏
 
- 同步任务
- 异步任务(宏任务和微任务)
- 微任务:Promise.then、Promise、async/await
- 宏任务:定时器(setTimeout setInterval)、事件监听、Ajax、DOM事件
PS:
 
1.async内遇到await先执行await,其中有异步代码的话--阻塞async后面代码执行,但不阻塞async外代码继续执行
 
2.promise执行resolve()或者reject()改变状态时才会把其then方法放进微任务队列
 
3.Event Loop
 
 (二) 旧解决异步问题方式-回调函数
 
异步问题:js单线程执行,如何实现异步
 
之前的方式:回调函数
 
缺点:过多函数嵌套导致出现”回调地狱”
 
| JavaScript// 最早解决异步问题:靠回调函数
 // 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对象来说 成功或失败后 不能再次改变其状态
 
即只能从等待状态转为成功状态 / 从等待状态转为失败状态
 
| JavaScript// 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个参数:分别对应成功后的回调和失败后的回调
| JavaScriptlet 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)
| JavaScriptlet 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对象:上一块代码报错
| JavaScriptlet 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对象
| JavaScriptlet 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的顺延
 
| finally -- 最终都会走这个finally
 | 
 
- 少写一个|不写参数
| JavaScript
 // 当你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失败的情况单独拎出来
| JavaScriptlet p4 = new Promise((resolve, reject) => {
 reject('失败')
 })
 p4.then(result => {
 console.log('处理成功');
 }).catch(error => {
 console.log('处理失败');
 })
 | 
 
- finally 最终都会走这个finally
| JavaScriptlet 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解决异步问题
 
| JavaScriptfunction 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.普通参数
 
 
2.参数是一promise对象
 
| JavaScriptlet p2 = new Promise((resolve, reject) => {
 reject('失败1')
 })
 resolve(p2)
 | 
 
3.是一个thenable (一不完整的promise对象)
 
thenable:就是一个对象中有一个then函数
 
| JavaScriptresolve({
 //then: function(resolve, reject) {}
 then(resolve, reject) {
 reject('失败2')
 }
 })
 | 
 
(七) Promise的静态方法
 
1、2. resolve、reject
 
| JavaScript// 最常规的两个静态方法  1.resolve  2.reject
 // 可以直接创建一个成功或者失败的promise对象
 let p1 = Promise.resolve('成功')
 console.log(p1);
 
 let p2 = Promise.reject('失败')
 console.log(p2);
 | 
 
3.all
 
| JavaScript// 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
 
| JavaScript// 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
 
| JavaScript// 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
 
| JavaScript//  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修饰后,变成异步函数,会返回一个promise对象
 await 不能单独使用,必须在async的修饰下使用
 个人理解:  async内遇到await时,若await的函数中有异步代码则不再向下执行-async内部阻塞,但是async外面的同步代码仍正常运行
 | 
 
(一) async
 
1.async的几种写法
 
具名函数、匿名函数、箭头函数、使用class声明类
 
| JavaScript// 具名函数的写法
 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('失败')
 
                }
 
            }
 
-   4.代码中有异常,抛出错误(代码运行并不终止) 那么整个promise就是一个失败态
| JavaScriptasync 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外部剩下同步代码的执行
 | 
 

 
| JavaScript// 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]值
 
        对数组/字符串:获取所有的索引+数组/字符串对应项
 
| JavaScriptlet 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 某些字符串进行前后的填充,来实现某种格式化效果
 
应用场景:比如需要对身份证、银行卡的前面位数进行隐藏
 
 
 
| JavaScriptlet cardNumber = '410233043254032403';
 // 截取前14位
 let sliceNumber = cardNumber.slice(0, 14)
 // 总长度cardNumber.length,减去sliceNumber.length剩余位数用'*'替换
 cardNumber = sliceNumber.padEnd(cardNumber.length, '*')
 console.log(cardNumber);//41023304325403****
 | 
 
(三)flat() 按指定的深度递归遍历数组
 
| JavaScript// 三维数组
 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
- 用途稍有不同:|| 是逻辑运算符偏向逻辑处理, ??主要为了简化代码
| JavaScriptlet info1 = 0
 info1 = info1 || '默认值'
 console.log(info1);//默认值
 
 let info2 = 0
 info2 = info2 ?? '默认值'
 console.log(info2);//0
 | 
 
 十二 箭头函数
 
(一)箭头函数实例
 
| JavaScriptvar 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形成暂时性死区
 
| JavaScript// 形成了暂时性死区
 // 由于let提升但是未初始化 导致在一片区域内 不能按照作用域链向上寻找变量
 // 这个区域叫暂时性死区
 var a = 1
 {
 console.log(a);//Cannot access 'a' before initialization
 let a = 2;//let声明提升但未初始化
 }
 |