es6学习

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)

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值