1 基础知识补充
ESnext--下一代js语言
任何人都可以向标准委员会(TC39),要求更改语言标准
- Stage 0 展示阶段
- Stage 1 征求意见阶段
- Stage 2 草案阶段
- Stage 3 候选阶段
- Stage 4 定案阶段(标准)
2 声明变量let const
块级作用域{}
let 相当于之前的var
const 常量
let注意点:
- 不存在变量提升,必须先定义再使用(TDZ--暂时性死区)
- 同一个作用域里不能重复定义
- for循环,循环里边是父级作用域,里面又一个
let a=12;
console.log(a)
//没有变量提升
function fn(){
alert(a);
let a=5;
}
//fn();
// 块级作用域
if(true){
let x=12;
//接下来只能在这里使用
}
//alert(x)
for(let i=0;i<10;i++){}
//console.log(i)
for(let j=0;j<3;j++){ //相当于父级作用域
let j='abc'//相当于子集作用域
console.log(j)
}
const注意点:
- 定义完变量不能修改
- 必须有值,不能后赋值
- 不存在变量提升
- 块级作用域
//const不能修改
const c=5;
//c=12;
console.log(c)
//下边这个可以添加
// const arr=['apple','banana'];
// arr.push('orange')
// console.log(arr)
//把数组冻结之后,就修改不了
const arr=Object.freeze(['apple','banana']);
//arr.push('orange')
//console.log(arr)
匿名函数
(function(){}()) 也可以改成{}
总结:以后尽量不用var,用let。如果想有的量不能改的话,再用const。
3 解构赋值(非常有用,特别是在ajax数据交互的时候)
let [a,b,c]=[12,5,6];
console.log(a,b,c)
注意:左右两边,结构要保持一致
json:
let json={
name:'strive',
age:18,
job:'码畜'
}
let {name,age,job}=json;
console.log(name,age,job)
let {name:n,age:g,job:a}=json;//也可以这么写,相当于起个别名
console.log(n,g,a)
解构的时候可以给默认值
let [a,b,c='暂无数据']=['aa','bb'];
console.log(a,b,c)
可以用数组有序这个特点来交换位置
let a=12;
let b=5;
[a,b]=[b,a];
console.log(a,b)
封装函数的时候返回
function getPos(){
return {
left:10,
top:20
}
}
let {left,top:t}=getPos();
console.log(left,t)
函数传参,可以给默认值
function show({a,b='默认'}){
console.log(a,b)
}
show({
a:1,
b:2
})
//也可以写成下边这样,参数有默认值
function show({a='默认1',b='默认2'}={}){
console.log(a,b)
}
show()
4 字符串模板和字符串新增
示例
let name='strive';
let age=18;
let str=`这个人叫${name},年龄是${age}岁`;
console.log(str)
<body>
<ul id="ul1">
</ul>
<script type="text/javascript">
let data=[
{title:'这是新闻的标题1',read:110},
{title:'这是新闻的标题2',read:120},
{title:'这是新闻的标题3',read:130},
{title:'这是新闻的标题4',read:140}
]
window.onload=function(){
var oul=document.querySelector('#ul1')
for(let i=0;i<data.length;i++){
var oli=document.createElement('li');
oli.innerHTML=`<span>${data[i].title}</span>
<span>阅读人数:${data[i].read}</span>
<a href="javascript:;">详情</a>`;
oul.appendChild(oli);
}
}
</script>
</body>
字符串新增的方法
①字符串查找----includes()
let str='apple banana pear';
alert(str.includes('banana'))//true false
if(navigator.userAgent.includes('Chrome')){
alert('是')
}else{
alert('不是')
}
②字符串是否以谁开头----startsWith()
let str='http://www.baidu.com';
let str2='http';
console.log(str.startsWith(str2))
③字符串是否以谁开头----endsWith()
let str='aaa.png';
console.log(str.endsWith('png'))
④字符串重复----repeat()
let str='aaa';
console.log(str.repeat(3))
⑤填充字符串
padStart(整个字符串长度,填充的东西)往前填充
padEnd(整个字符串长度,填充的东西)往后填充
let str='apple';
let padStr='xxx';
console.log(str.padStart(str.length+padStr.length,padStr));
5 函数默认参数、箭头函数和剩余参数
函数默认参数示例
function show(a='欢迎',b='牧马人'){
console.log(a,b)
}
show('welcome')
注意:函数的参数默认已经定义了,不能再用let或者const声明。
function show(a=18){
let a=101;
console.log(a);//报错
}
show(12);
扩展运算符(剩余运算符,又叫reset运算符)
let arr=['apple','banana','orange']
console.log(arr)
console.log(...arr)
function show(...a){
console.log(a)
}
show(1,2,3,4,5)
扩展运算符和函数的结合
function show(...a){
// console.log(arguments)
//let a=Array.prototype.slice.call(arguments);
return a.sort();
}
console.log(show(-2,101,6,70,8));
function show1(a,b,c){
console.log(a,b,c)
}
show1(...[1,9,8])
function show2(a,b,...c){
console.log(a,b,c)
}
show2(1,2,3,4,5)
Array.from()的功能与...类似
let arr=[1,2,3,4,5]
let arr2=Array.from(arr)
//let arr2=[...arr]
console.log(arr,arr2)
let str='a-b-c';
let arr3=Array.from(str)
console.log(arr3)//['a','-','b','-','c']
箭头函数
()=>return的东西
()=>{语句}
let show=(a,b)=>a+b;
console.log(show(12,5))
let show=(a,b)=>{
console.log(a+b);
}
show(12,5);
箭头函数注意:
①this问题,定义函数所在的对象,不再是运行时所在的对象
var id=10;
//用var定义一个全局变量是属于window,let和const不是
let json={
id:1,
show:function(){
setTimeout(()=>{
alert(this.id)
},1000)
}
}
json.show();//弹框1
②箭头函数里没有arguments,可以用扩展运算符
let show=(...args)=>{
console.log(args)
//console.log(arguments)报错
}
show(1,2,3,4,5)
③箭头函数不能当构造函数
let show=()=>{
this.name='abc';
}
let s=new show();
alert(s.name)//报错
补充点
//es2017以后,函数参数最后的逗号可以有了
function show(a,b,c,){
console.log(a,b,c)
}
show(1,2,3,)
6 数组循环
1,2,3,4,5可以接收两个参数,第一个是回调函数,第二个是this指向谁(默认指向window),但是如果用箭头函数就改变不了this的指向了。
①arr.forEach()
let arr=['apple','banana','orange','tomato']
arr.forEach((val,index,arr)=>{
console.log(this,val,index,arr)
},123)
②arr.map() 正常情况下,需要配合return,返回的是一个新的数组。如果没有return,相当于forEach
let arr=[
{
title:'aaa',read:10000,hot:true
},
{
title:'bbb',read:10000,hot:false
},
{
title:'ccc',read:10000,hot:true
}
]
let newArr=arr.map((val,index,arr)=>{
let json={}
json.t=`~~~${val.title}----`;
json.r=val.read+200;
json.hot=val.hot==true && '真棒';
return json;
})
console.log(newArr)
③arr.filter()过滤,过滤不合格的元素,如果回调函数返回的是true,就留下来
let arr=[
{
title:'aaa',read:10000,hot:true
},
{
title:'bbb',read:10000,hot:false
},
{
title:'ccc',read:10000,hot:true
}
]
let newArr=arr.filter((item,index,arr)=>{
return item.hot==true
})
console.log(newArr)
④arr.some() 类似查找,只有有一个元素符合条件就返回true
let arr=['apple','banana','orange']
let newArr=arr.some((item,index)=>{
return item=='banana'
})
console.log(newArr)
⑤arr.every() 数组里面所有的元素都符合条件就返回true
let arr=[1,3,5,7,9,10]
let newArr=arr.every((item,index)=>{
return item%2==1
})
console.log(newArr)
⑥ar.reduce() 从左往右 求和、求阶乘 第一个参数为前一个,第二个参数为当前的,第三个为索引,第四个为数组本身
let arr=[2,2,2]
let newArr=arr.reduce((prev,cur,index,arr)=>{
//return prev+cur;
//return Math.pow(prev,cur)
return prev**cur
})
console.log(newArr)
⑦arr.reduceRight() 从右往左
let arr=[2,2,2]
let newArr=arr.reduceRight((prev,cur,index,arr)=>{
//return prev+cur;
//return Math.pow(prev,cur)
return prev**cur
})
console.log(newArr)
⑧for...of循环
arr.keys() 数组下标
arr.entries() 数组某一项
let arr=[1,2,3]
for(let val of arr){
console.log(val)
}
for(let index of arr.keys()){
console.log(index)
}
for(let item of arr.entries()){
console.log(item)
}
for(let [key,val] of arr.entries()){
console.log(key,val)
}
7 数组新增
扩展运算符扩展
<body>
<ul>
<li>11</li>
<li>22</li>
<li>33</li>
<li>44</li>
</ul>
<script type="text/javascript">
var ali=document.querySelectorAll('ul li')
let arr=[...ali]
console.log(arr)
</script>
</body>
Array.from() 作用:把类数组(具备length这个属性就差不多了)转成数组,
var ali=document.querySelectorAll('ul li')
let arr=Array.from(ali)
console.log(arr)
//函数转数组
function show(){
let args=Array.from(arguments)
console.log(args)
}
show(1,2,3,4,5)
//字符串转数组
let str='strive'
let arr=Array.from(str)
console.log(arr)
//json数据转数组
let json={
0:'apple',
1:'banana',
2:'orange',
length:3
}
let arr1=Array.from(json)
console.log(arr1)
Array.of() 把一组值转成数组
let arr=Array.of('apple','banana','orange')
console.log(arr)
arr.find() 找到第一个符合条件的数组成员,如果没有找到,返回undefined
let arr=[23,90,101,80,100]
let res=arr.find((val,index,arr)=>{
return val>100;
})
console.log(res)
arr.findIndex() 找位置,没找到返回-1
let arr=[23,90,101,80,100]
let res=arr.findIndex((val,index,arr)=>{
return val>100;
})
console.log(res)
arr.fill(填充的东西,开始位置,结束位置) 填充数据
let arr=new Array(3);
arr.fill('默认值',0,1)
console.log(arr)
arr.includes()包含
let arr=['apple','banana','orange']
let b=arr.includes('orange')
console.log(b)
8 对象语法及新增
对象简介语法:
let name='strive';
let age=18;
let json={
name,//name:name
age, //age:age
showA(){//不要用箭头函数
return this.name
}
}
console.log(json.showA())
Object.is() 比较两个值是否相等
let b=Object.is(NaN,NaN)
console.log(b)//true
let c=Object.is(+0,-0)
console.log(c)//false
Object.assign(目标对象,source1,source2...) 用来复制对象或合并参数
//合并参数
let json={a:1};
let json2={b:2};
let json3={c:3};
let obj=Object.assign({},json,json2,json3)
console.log(obj)
//复制对象
let arr=['apple','banana','orange'];
let arr2=Object.assign([],arr)
arr2.push('tomato')
console.log(arr2)
console.log(arr)//没有tomato
Object.keys() Object.entries() Object.values()
let json={
a:1,
b:2,
c:3
}
for(let key of Object.keys(json)){
console.log(key)
}
9 promise
作用:解决异步问题
基本语法:
let a=1;
let promise=new Promise(function(resolve,reject){
//resolve成功调用
//reject失败调用
if(a==10){
resolve('成功')
}else{
reject('失败')
}
});
promise
.then(res=>{
console.log(res)
})
.catch(err=>{//catch为reject发生错误的别名
console.log(err)
})
Promise.resolve('aa'):将现有的东西,转成一个promise对象,resolve状态,即成功状态
/*
let p1=Promise.resolve('aaa')
p1.then(res=>{
console.log(res)
})*/
//上面的一段话等价于下面的
let p1=new Promise(resolve=>{
resolve('aaa')
})
p1.then(res=>{
console.log(res)
})
Promise.reject('aa'):将现有的东西,转成一个promise对象,reject状态,即失败状态
// let p1=Promise.reject('aaa')
// p1.then(res=>{
// console.log(res)
// }).catch(err=>{
// console.log(err)
// })
//上面的一段话等价于下面的
let p1=new Promise((resolve,reject)=>{
reject('aaa')
})
p1.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
Promise.all([p1,p2,p3]):把promise打包,扔到一个数组里面,还是一个promise对象,必须确保所有的状态都是resolve状态,都是成功状态
//必须确保所有的状态都是resolve状态,都是成功状态
let p1=Promise.resolve('aaa')
let p2=Promise.resolve('bbb')
let p3=Promise.resolve('ccc')
Promise.all([p1,p2,p3]).then(res=>{
let [res1,res2,res3]=res;
console.log(res1,res2,res3)
})
Promise.race([p1,p2,p3]):只要有一个成功了就返回
let p1=Promise.reject('aaa')
let p2=Promise.reject('bbb')
let p3=Promise.resolve('ccc')
Promise.race([p1,p2,p3]).then(res=>{
let [res1,res2,res3]=res;
console.log(res1,res2,res3)
}).catch(err=>{
console.log(err)
})
模拟用户登录-获取信息
let status=1;
let userlogin=(resolve,reject)=>{
setTimeout(()=>{
if(status==1){
resolve({data:'登录成功',msg:'xxx',token:'dd'})
}else{
reject('失败了')
}
},2000)
}
let getuserinfo=(resolve,reject)=>{
setTimeout(()=>{
if(status==1){
resolve({data:'获取信息成功',msg:'xxx',token:'dd'})
}else{
reject('失败了')
}
},1000)
}
new Promise(userlogin).then(res=>{
console.log(res)
return new Promise(getuserinfo)
}).then(res=>{
console.log(res)
})
10 模块化
需要清楚两个问题:
①如何定义模块
需要放到服务器环境
export 东西
②如何使用
import 东西
<script type="module"></script>
import注意:
1 import可以是绝对路径,也可是相对路径
2 无论引入多少次,只会导入一次
3 import './1.js'这么引用相当于引用文件
4 有提升效果,import这句话可以自动提升到顶部
5 导出的模块如果有内容更改了,外面也会更改
写法1
export const a=12;
export const b=5;
import {a,b} from './1.js'
console.log(a,b)
写法2
const a=12;
const b=5;
const c=101;
export {
a,
b,
c
}
import {a,b,c} from './1.js'
console.log(a,b,c)
写法3
const a=12;
const b=5;
const c=101;
export {
a as aaa,
b as bbb,
c as ccc
}
import {aaa,bbb,ccc} from './1.js'
console.log(aaa,bbb,ccc)
写法4
const a=12;
const b=5;
const c=101;
export {
a as aaa,
b as bbb,
c as ccc
}
import {aaa as a,bbb as b,ccc as c} from './1.js'
console.log(a,b,c)
写法5
const a=12;
const b=5;
const c=101;
export {
a as aaa,
b as bbb,
c as ccc
}
import * as module from './1.js'
console.log(module)
写法6
export default 12;
export const cc=1;
export const dd=3;
//导入时如果导出有default就不用加{}
import a,{cc,dd} from './1.js'
console.log(a,cc,dd)
写法7
//2.js
export const a=1;
export const b=2;
//1.js
// const a=12;
// const b=5;
import {a,b} from './2.js'
const sum=()=>{
console.log(a+b)
return a+b;
}
const show=()=>{
console.log('show')
return 1;
}
class Person{
constructor(name,age){
this.name=name;
this.age=age;
}
showName(){
return '我的名字是'+this.name;
}
}
export {
a,
b,
sum,
show
}
export default{
Person
}
import mod,{show,sum,a,b} from './1.js'
let p1=new mod.Person('fufu');
console.log(p1.showName())//fufu
show()//show
sum()//3
console.log(a,b)//1 2
动态引入import(),默认import语法不能写到if条件判断里,返回值是promise对象
import('./1.js').then(res=>{
console.log(res)
})
动态引入优点:按需加载;可以写到if里;路径也可是动态的
可以结合promise来用
Promise.all([
import('./1.js'),
import('./2.js')
]).then(([mod1,mod2])=>{
console.log(mod1)
console.log(mod2)
})
也可以结合async和await来用
async function main(){
const m1=await import('./1.js');
const m2=await import('./2.js');
console.log(m1,m2)
}
main()
es6里模块化默认使用的是严格模式
11 类和继承
普通构造函数的写法
function Person(name,age){
this.name=name;
this.age=age;
}
//第一种写法
/*
Person.prototype.showName=function(){
return `名字为:${this.name}`;
}
Person.prototype.showAge=function(){
return `年龄为:${this.age}`;
}
*/
//第二种写法
Object.assign(Person.prototype,{
showName(){
return `名字为:${this.name}`;
},
showAge(){
return `年龄为:${this.age}`;
}
})
let p1=new Person('strive',10)
console.log(p1)
类的简单案例
class Person{//名字可以大写,也可以小写
constructor(name,age){//构造方法,只要调用new就自动执行
this.name=name;
this.age=age;
}//不需要加,
showName(){
return `名字为:${this.name}`
}//不需要加,
showAge(){
return `年龄为:${this.age}`
}
}
let p1=new Person('strive',18)
console.log(p1.showName())//名字为strive
另一种写法表达式形式的定义
const Person=class {
constructor(name,age){//构造方法,只要调用new就自动执行
this.name=name;
this.age=age;
}//不需要加,
showName(){
return `名字为:${this.name}`
}//不需要加,
showAge(){
return `年龄为:${this.age}`
}
}
let p1=new Person('strive',18)
console.log(p1.showName())//名字为strive
变量名表示方法名
let aaa='sss';
let bbb='method';
class Person{
constructor(name,age){//构造方法,只要调用new就自动执行
this.name=name;
this.age=age;
}//不需要加,
showName(){
return `名字为:${this.name}`
}//不需要加,
showAge(){
return `年龄为:${this.age}`
}
[aaa](){
return '随便了';
}
[aaa+bbb](){
return 'cccc'
}
}
let p1=new Person('strive',18)
console.log(p1[aaa]())//随便了
console.log(p1.sss())//随便了
console.log(p1[aaa+bbb]())//cccc
console.log(p1.sssmethod())//cccc
注意:
1 es6里的class没有提升的功能,在es5,函数模拟是可以提升的。
let p1=new Person()
console.log(p1)//报错
class Person{
constructor(){//构造方法,只要调用new就自动执行
this.name='aaa';
}
}
2 this比之前轻松多了
矫正this:
1 fn.call(this指向谁,arg1,arg2...)
2 fn.apply(this指向谁,[arg1,arg2...])
3 fn.bind() 只负责矫正
class Person{
constructor(){
this.name='aaa';
//矫正this
this.showName=this.showName.bind(this)
}
showName(){
console.log(this)
return `名字为:${this.name}`
}
}
let p1=new Person()
let {showName}=p1;
console.log(showName())
class里面取值函数(getter),存值函数(setter)
class Person{
constructor(){
}
get aaa(){
return `获取aaa的属性`;
}
set aaa(val){
console.log('设置aaa值为'+val)//设置aaa值为123
}
}
let p1=new Person()
p1.aaa="123"
console.log(p1.aaa)//获取aaa的属性
静态方法:类身上的方法
class Person{
constructor(){
}
showName(){
return '这是showName方法'
}
static aaa(){
return '这是静态方法'
}
}
let p1=new Person()
console.log(p1.showName())//这是showName方法
console.log(Person.aaa())//这是静态方法
继承:
之前继承的示例
//父类
function Person(name){
this.name=name;
}
Person.prototype.showName=function(){
return `名字是${this.name}`
}
// 子类
function Student(name,skill){
Person.call(this,name)//继承属性
this.skill=skill;
}
Student.prototype=new Person();//继承方法
let stu1=new Student('strive','逃学')
console.log(stu1)
现在继承的示例
//父类
class Person{
constructor(name){
this.name=name;
}
showName(){
console.log('父类的里的showName')
return `名字为${this.name}`
}
}
// 子类
class Student extends Person{
constructor(name,skill){
super(name);//必填的,继承父类的
this.skill=skill;
}
// 父类里含有的方法
showName(){
super.showName()//父级的方法执行
// 再做子类的事情
console.log('子类的里的showName')
}
// 子类自己的方法
showSkill(){
return `哥们的技能为${this.skill}`
}
}
let stu1=new Student('strive','逃学')
console.log(stu1.showName())
拖拽的案例
//普通拖拽--父类
class Drag{
constructor(id){
this.oDiv=document.querySelector(id);
this.disX=0;
this.disY=0;
this.init();
}
init(){
this.oDiv.onmousedown=function(ev){
this.disX=ev.clientX-this.oDiv.offsetLeft;
this.disY=ev.clientY-this.oDiv.offsetTop;
document.onmousemove=this.fnmove.bind(this);
document.onmouseup=this.fnup.bind(this);
return false;
}.bind(this);
}
fnmove(ev){
this.oDiv.style.left=ev.clientX-this.disX+'px';
this.oDiv.style.top=ev.clientY-this.disY+'px';
}
fnup(){
document.onmousemove=null;
document.onmouseup=null;
}
}
// 子类
class LimitDrag extends Drag{
fnmove(ev){
super.fnmove(ev);
//限制范围
if(this.oDiv.offsetLeft<=0){
this.oDiv.style.left=0;
}
}
}
//调用
new Drag('#div1')
new LimitDrag('#div2');
12 Symbol 和 generator
① 新增的数据类型:symbol 使用情况一般
定义:
let syml=Symbol('aaa');
注意:
1 Symbol前边不能加new
2 Symbol() 返回的是唯一的值,作为一个key,定义一些唯一或者私有的东西
3 symbol是一个单独的数据类型,就叫symbol
4 如果symbol作为key的话,用for in循环是出不来的
let syml=Symbol('aaa');
let json={
a:'apple',
b:'banana',
[syml]:'bbb'
}
for(let item in json){
console.log(item)//a b
}
② generate函数 生成器 解决异步、深度嵌套的问题
//*两边可以有空格,也可以没有,放在function和函数名之间
function * gen(){
yield 'welcome';
yield 'to';
return 'home'
}
//调用
let g1=gen();
console.log(g1.next())//{vale:'welcome',done:false}
console.log(g1.next())//{vale:'to',done:false}
console.log(g1.next())//{vale:'home',done:true}
console.log(g1.next())//{value: undefined, done: true}
上述的调用为手动输出,非常麻烦
for...of循环generate return的东西不会遍历
//*两边可以有空格,也可以没有,放在function和函数名之间
function * gen(){
yield 'welcome';
yield 'to';
return 'home'
}
//for...of循环generate return的东西不会遍历
let g1=gen();
for(let val of g1){
console.log(val)//welcome to
}
generate不仅可以配合for...of,还可以
1 解构赋值
function * gen(){
yield 'welcome';
yield 'to';
return 'home'
}
let [a,b,c]=gen();
console.log(a,b,c)//welcome to undefined
2 扩展运算符
function * gen(){
yield 'welcome';
yield 'to';
return 'home'
}
console.log(...gen())//welcome to
3 Array.from()
function * gen(){
yield 'welcome';
yield 'to';
return 'home'
}
console.log(Array.from(gen()))//['welcome','to']
generate结合axios数据请求案例
function *gen(){
let val=yield 'itstrive';
yield axios.get(`https://api.github.com/users/${val}`);
}
let g1=gen();
let username=g1.next().value;
console.log(username)//itstrive
g1.next(username).value.then(res=>{
console.log(res)
})
异步:不连续,上一个操作没有执行完,下一个操作照样开始
同步:连续,上一个操作没有执行完,下一个操作没法开始
异步解决方案:回调函数,事件监听,发布订阅模式,promise,generate,async等等
13 async、await
读取文件的案例
const fs = require('fs');
//封装成一个promise的版本
const readFile = function(file){
return new Promise((resolve,reject)=>{
fs.readFile(file,(err,data)=>{
if(err) reject(err);
resolve(data);
})
})
}
//promise方式
/*
readFile('./data/a.txt').then(res=>{
console.log(res.toString())//aaaaaa;
return readFile('./data/b.txt')
}).then(res=>{
console.log(res.toString())//bbbbbb;
return readFile('./data/c.txt')
}).then(res=>{
console.log(res.toString())//ccccc;
})
*/
//generate方式
/*
function *gen(){
yield readFile('./data/a.txt');
yield readFile('./data/b.txt');
yield readFile('./data/c.txt');
}
let g1 = gen();
g1.next().value.then(res=>{
console.log(res.toString())
return g1.next().value;
}).then(res=>{
console.log(res.toString())
return g1.next().value;
}).then(res=>{
console.log(res.toString())
})
*/
//async方式
async function fn(){
let f1=await readFile('./data/a.txt')
console.log(f1.toString())
let f2=await readFile('./data/b.txt')
console.log(f2.toString())
let f3=await readFile('./data/c.txt')
console.log(f3.toString())
}
fn();
语法:
async function fn(){//表示异步,这个函数里面有异步任务
let result=await xxx; //表示后面结果需要等待
}
特点:
1 await只能放到async中
2 相比generate语义化更强
3 await后面可以是promise对象,也可以是数字,字符串,布尔等
4 async函数返回的是一个promise对象
async function fn(){
return 'welcome'
}
console.log(fn())//promise对象
fn().then(res=>{
console.log(res)//welcome
})
5 只要await语句后面promise变成reject,那么整个async函数就会中断执行
async function fn(){
throw new Error('error');
}
fn().then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)//error
})
async function fn(){
await Promise.reject('出现问题了');
}
fn().then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)//出现问题了
})
async function fn(){
await Promise.reject('出现问题了');
let a=await Promise.resolve('success');
console.log(a)//不执行了,因为上边出错了
}
fn().then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)//出现问题了
})
如何避免await后面出现reject,就影响后面代码的执行呢?
1 try{
}catch(e){
}
async function fn(){
try{
await Promise.reject('出现问题了');
}catch(e){}
let a=await Promise.resolve('success');
console.log(a)//success
}
fn().then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
2 promise本身catch也可以
async function fn(){
await Promise.reject('出现问题了').catch(err=>{
console.log(err)//出现问题了
});
let a=await Promise.resolve('success');
console.log(a)//success
}
fn().then(res=>{
console.log(res)
})
建议都结合try和catch使用
async function fn(){
try{
var f1=await readFile('./data/a.txt')
var f2=await readFile('./data/b.txt')
var f3=await readFile('./data/c.txt')
}catch(e){}
console.log(f1.toString())
console.log(f2.toString())
console.log(f3.toString())
}
console.log(fn());
当几个文件之间没有关联时可以用下面的写法
async function fn(){
let [a,b,c]=await Promise.all([
await readFile('./data/a.txt'),
await readFile('./data/b.txt'),
await readFile('./data/c.txt')
])
console.log(a.toString())
console.log(b.toString())
console.log(c.toString())
}
console.log(fn());
14 Set和WeakSet
set数据结构,类似于数组,但是里边不能有重复的值,有的话会自动忽略
let setArray=new Set(['a','b','c']);
console.log(setArray)
方法一:添加
let setArray=new Set();
setArray.add('a')
console.log(setArray)
方法二:删除
let setArray=new Set(['a','b']);
setArray.delete('a')
console.log(setArray)
方法三:判断是否含有此值
let setArray=new Set(['a','b']);
setArray.delete('a')
console.log(setArray.has('a'))//false
属性1:长度
let setArray=new Set(['a','b']);
console.log(setArray.size)//2
属性2:清除
let setArray=new Set(['a','b']);
setArray.clear()
console.log(setArray)
循环1:for...of
let setArray=new Set(['a','b','c']);
for(let item of setArray){//默认是values
console.log(item)//a b c
}
for(let item of setArray.keys()){
console.log(item)//a b c
}
for(let item of setArray.values()){
console.log(item)//a b c
}
for(let [k,v] of setArray.entries()){
console.log(k,v)
}
循环2:forEach
let setArray=new Set(['a','b','c']);
setArray.forEach((value,index)=>{
console.log(value,index)
})
链式操作
let setArray=new Set();
setArray.add('a').add('b').add('c')
console.log(setArray)
用处:数组去重
let arr=[1,2,3,4,5,6,7,6,5,4,5,6];
let set=[...new Set(arr)];
console.log(set)
set数据结构变成数组 [...set]
想让set使用数组的map和filter循环
//想打印出来的为2,4,6
let set=new Set([1,2,3]);
set=new Set([...set].map(val=>val*2))
console.log(set)
//想留下来偶数
let set=new Set([1,2,3,5,6,7]);
set=new Set([...set].filter(val=>val%2==0))
console.log(set)
set注意的地方
new Set([]) 存储数组
new WeakSet({}) 存储json,这种写法不靠谱,没有size属性,没有clear,有has、delete和add
let set=new Set();
let json={
a:1,
b:2
}
let json2={
a:1,
b:2
}
set.add(json).add(json2)
console.log(set)//{{a:1,b:2},{a:1,b:2}}
set.forEach(item=>{
console.log(item)
})
let set1=new Set({a:1,b:2})
console.log(set1)//报错
初始往里边添加json是不行的,可以用add添加
15 Map和WeakMap
map类似json,但是json的key只能是字符串,map的key可以是任意类型
使用:
let map=new Map();
let json={
a:1,
b:2
}
map.set('a','aa')//设置一个值
map.set(json,'aaa')
console.log(map)//{"a" => "aa", {…} => "aaa"}
console.log(map.get(json))//获取一个值
map.delete(json)//删除
console.log(map.has(json)) //判断是否含有
map.clear()//清空
循环跟set一模一样
let map=new Map();
let json={
a:1,
b:2
}
map.set('a','aa')
map.set(json,'aaa')
for(let [key,value] of map){
console.log(key,value)
}
map.forEach((value,key)=>{
console.log(value,key)
})
WeakMap() key只能是对象,用处不大
let map=new WeakMap();
let json={
a:1,
b:2
}
map.set(json,'aaa')
console.log(map)
16 数字变化和Math新增的东西
二进制(binary),前边加上一个0b,由0和1组成
let a=0b010101;
console.log(a)//21
八进制(octal):前边加0o,由0,1,2,3,4,5,6,7组成
let a=0o666;
console.log(a)//438
十六进制:#ccc,由0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f组成
Number.isNaN()
let a=12;
console.log(isNaN(a))//false
console.log(Number.isNaN(a))//false
Number.isFinite() 判断是不是数字
let a=12;
console.log(Number.isFinite(a))//true
Number.isInteger() 判断是不是整数
let a=12;
let b=1.5;
console.log(Number.isInteger(a))//true
console.log(Number.isInteger(b))//false
Number.parseInt()
Number.parseFloat()
安全整数:-(2**53-1) ~ (2**53-1) 包含边界值
Number.isSafeInteger() 判断是不是安全整数
let a=2**53-1;
console.log(Number.isSafeInteger(a))//true
//最大安全整数
console.log(Number.MAX_SAFE_INTEGER)//2**53-1
//最小安全整数
console.log(Number.MIN_SAFE_INTEGER)//-(2**53-1)
Math新增的东西
//Math.trunc()保留整数部分
console.log(Math.trunc(4.56));//4
//Math.sign()判断一个数是正数还是负数
console.log(Math.sign(-5))//-1
console.log(Math.sign(5))//1
console.log(Math.sign(-0))//-0
console.log(Math.sign(0))//0
console.log(Math.sign('abc'))//NaN
//Math.cbrt()计算一个数的立方根
console.log(Math.cbrt(27))//3
17 Es9新增的东西
原来的正则:
let str='2018-03-20';
let reg=/(\d{4})-(\d{2})-(\d{2})/;
let date=str.match(reg);
let year=date[1];
let month=date[2];
let day=date[3];
console.log(year,month,day)//2018 03 20
1 命名捕获:语法(?<名字>)
let str='2018-03-20';
let reg=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let {year,month,day}=str.match(reg).groups;
console.log(year,month,day)//2018 03 20
反向引用命名捕获:语法 \k<名字>
let reg=/^(?<strive>welcome)-\k<strive>-\1$/;
let str='a-a'
let str2='strive-strive'
let str3='welcome-welcome'
let str4='welcome-welcome-welcome'
console.log(reg.test(str))//false
console.log(reg.test(str2))//false
console.log(reg.test(str3))//false
console.log(reg.test(str4))//true \1是复制第一个,\k也可以用\1
替换replace
let str='2018-03-20'
let reg=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
//03/20/2018
str = str.replace(reg,'$<month>/$<day>/$<year>')
console.log(str)//03/20/2018
let str='2018-03-20'
let reg=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
str = str.replace(reg,(...args)=>{
let {year,month,day}=args[args.length-1]
return `${day}/${month}/${year}`
})
console.log(str)//20/03/2018
2 dotAll模式
let reg=/^\w+.\w+$/s;
let str='welcome\n51mmr';
console.log(reg.test(str))
//true.能匹配任何东西,除了\n,如果想匹配\n,就在最后加个s
3 标签函数
function fn(args){
return args[0].toUpperCase();
}
console.log(fn`welcome`)//WELCOME
18 Proxy的使用
proxy:代理,扩展(增强)对象的一些功能,proxy是设计模式的一种,是代理模式
作用:比如vue中拦截,预警、上报、扩展功能、统计和增强对象等等
语法:let obj=new Proxy(被代理的对象,对代理的对象做的操作)
handler
{
set(){}, 设置的时候干的事
get(){}, 获取干的事情
deletePropty(){}, 删除
has(){}, 问你有没有这个东西
apply(){}, 调用函数的处理
......
}
get() 获取
let obj={
name:'strive'
}
let newObj = new Proxy(obj,{
get(target,property){
console.log(target,property)//{name: "strive"} "aaa"
return target[property];
}
})
console.log(newObj.name);//strive
set() 设置
//设置一个年龄是整数,且范围不超过200
let obj=new Proxy({},{
set(tar,pro,value){
if(pro == 'age'){
if(!Number.isInteger(value)){
throw new TypeError(`年龄必须为整数`)
}
if(value>200){
throw new RangeError(`年龄超了`);
}
}
tar[pro]=value;
}
})
obj.name='strive'
obj.age=200;
console.log(obj)
deleteProperty() 删除
has() 是否含有
let json={
a:1,
b:2
}
let newJson=new Proxy(json,{
deleteProperty(tar,pro){
delete tar[pro]
},
has(tar,pro){
return pro in tar;
}
})
console.log('a' in newJson);//true
// delete newJson.a;
console.log(newJson)
apply() 调用函数的处理
function fn(){
return '我是函数'
}
let newFn=new Proxy(fn,{
apply(){
return '函数么?'
}
})
console.log(newFn())//函数么?
案例1:实现一个,访问一个对象身上属性,默认不存在的时候给undefined,如果不存在就返回错误(警告)信息
let obj={
name:'strive'
}
let newObj = new Proxy(obj,{
get(target,property){
if(property in target){
return target[property];
}else{
//throw new ReferenceError(`${property}不在此对象上`)
console.warn(`${property}不在此对象上`)
}
}
})
console.log(newObj.name);//strive
console.log(newObj.age);//报错
案例2:
const DOM = new Proxy({},{
get(tar,pro){
console.log(tar,pro) //pro为div
return function(attr={},...children){
console.log(attr,children)
const el=document.createElement(pro);
//添加属性
for(let key of Object.keys(attr)){
el.setAttribute(key,attr[key])
}
//添加子元素
for(let child of children){
if(typeof(child)=='string'){
child=document.createTextNode(child);
}
el.appendChild(child)
}
return el;
}
}
});
let oDiv=DOM.div(
{id:'div1'},
'我是div1',
'呵呵呵',
DOM.a({href:'http://www.baidu.com'},'访问我')
);
console.log(oDiv)
19 Reflect的使用
Reflect反射
function sum(a,b){
return a+b;
}
let newSum = new Proxy(sum,{
apply(tar,context,args){
//console.log(tar,context,args)
//console.log(...arguments)
return Reflect.apply(...arguments)**2;
}
})
console.log(newSum(2,3))//25
Reflect.apply(调用的函数,this指向,参数数组)
let res=Reflect.apply(Math.ceil,null,[9.8])
console.log(res)//10
function show(...args){
console.log(this)
console.log(args)
}
//第一种写法
//show.call('abc',1,2,3)
//第二种写法
//show.apply('abcd',[1,2,3])
//第三种写法
Reflect.apply(show,'aaa',[1,2,3])
通过Reflect拿到语言内部的东西
console.log('assign' in Object)//true
console.log(Reflect.has(Object,'assign'))//true
let json={
a:1,
b:2
}
Reflect.deleteProperty(json,'a');
console.log(json)