es6语法学习

es6

1.环境搭建

  • 方法一
下载node.js,在git-bash.exe中输入 node -v 显示node.js版本
输入 npx es10-cli create es2019初始化项目
cd 到项目目录
npm start
访问http://localhost:8080
  • 方法二
使用npx命令 npm版本 >5.2.0
npm install es10-cli -g
es10-cli create projectName
cd projectName
npm start
  • 方法三
如果都失败
git clone https://github.com/cucygh/es-cli.git es2020
cd 2020
npm install
npm start

在这里插入图片描述

  • 如何切换npm源

参考文章:http://www.imooc.com/article/254541

  • 配置编辑器

在这里插入图片描述

2.ES6语法

  • 作用域
    • 全局作用域
    • 块状作用域
    • 函数作用域
    • 动态作用域
<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>

</body>
<script type="text/javascript">
	//全局作用域
	var abc = 1234 //全局变量
	console.log(abc)
	abcd = 2345 //作为window(全局对象)的属性存在 不是真正意义上的全局变量
	console.log(abcd)
	function test (){
		ab = 45 //不是函数作用域 是全局作用域 挂在window上作为window的属性
	}
	test()


	//函数作用域
	function test1(){
		var a =3 //局部作用域 函数作用域
		return a + 4 //通过return 或者闭包的形式向外传递数据
	}
	console.log(test1())
	console.log(a) //报错 Uncaught ReferenceError: a is not defined


	function test3(){
		var a =3 
		function test4(){
			var b=4 //函数作用域会向上找 如果a +b+c,找不到c会找window对象 没有就返回undefined
			return a+b
		}
		return test4 //闭包
	}


	//块状作用域
	function test2(){
		var a =3 
		if(a===3){   //可以认为花括号内部就是一个独立的块作用域 
			let b=4  //不会向上找了 没用上下级作用域链 使用var会变量提升
			console.log('abc')
		}else{
			console.log('abcd')
		}

		console.log(b)
		return a+ 4
	}
	console.log(test2())


	//动态作用域 
	window.a=3
	function test(){
		console.log(this.a)
	}
	test()
	test.bind({a:100})() 
	//bind  之后返回一个新的函数,这个函数可以保持传递的this上下文
</script>
</html>

Let

  • let声明的变量拥有块级作用域
  • let声明的全局变量不是全局对象(window)的属性
  • 用let重定义变量会抛出一个语法错误
  • let声明的变量不会进行变量提升
<script type="text/javascript">
	{
		let a =1
		console.log(a)
	}
	console.log(a) //块状作用域 在外部不能访问 Uncaught ReferenceError: a is not defined

	var b =3
	let c =4
	console.log(b,c)
	console.log(window.b,window.c) //var定义的全局变量可以通过window访问 let定义的全局变量不能

	var b =4 //var定义的变量可以重复
	console.log(b)

	let c =5 //let定义的变量不可以重复 Identifier 'c' has already been declared
	console.log(c)

	//let定义的变量不会变量提升
</script>

const

  • const拥有let的特性,除此之外const只能定义常量
  • const定义的变量不能修改 Assignment to constant variable
  • const不能先声明再赋值 Missing initializer in const declaration
//const拥有let的特性,除此之外const只能定义常量
	const a =2
	a=3
	console.log(a) //Assignment to constant variable. 不能修改变量

	const b
	b=3 //不能先声明在赋值 Missing initializer in const declaration

阅读:
1.什么是作用域
JavaScript深入之词法作用域和动态作用域
深入理解js中声明提升,作用域(链)和this关键字

输出什么 如何根据i的顺序输出
	for(var i=0;i<3;i++){
		setTimeout(function(){
			console.log(i)
		},1000);
	}  =>输出33
  https://www.cnblogs.com/wl0804/p/11987833.html

	以下代码发生什么
	console.log(a)
	let a =1  ==>Uncaught ReferenceError: Cannot access 'a' before initialization

Array

  • es5中数组遍历有多少种方法
  • 优点与缺点
<script type="text/javascript">
	const arr =[1,2,3,4,5];

	//for循环
	for (let i = 0; i < arr.length; i++) {
		if(arr[i]===2){
			continue;
		}
		console.log(arr[i])
	}

	//forEach
	arr.forEach(function(item){
		//不支持break与continue语法
		console.log(item)
	})

	//every
	arr.every(function(item){
		console.log(item)
		//默认不继续循环遍历
		return true
	})

//every实现break功能
	arr.every(function(item){
		if(item===2){
			return false
		}
		console.log(item)
	})

	//every实现continue功能
	arr.every(function(item){
		if(item===2){

		}else{
			console.log(item)
		}
		return true
	})

//for in 主要是操作对象的 也可以遍历数组 但是会有问题
	//数组也是对象的一种
	arr.a = 8 //数组的索引不应该是a
	for(let index in arr){
		console.log(index,arr[index])
	}

//for in支持break与cotinue
	for(let index in arr){
		if(index ==2){ //这里的index是字符串,而不是数值,需要用==才能break成功 ===判断数值和类型,==只判断数值不判断类型
			break;
		}
		console.log(index,arr[index])
	}

es6遍历语法

//for of 遍历自定义数据结构 既不是数组也不是object
	for(let item of arr){
		console.log(item)
	}

	const price= {
		A:[1.5,2.5,3.5],
		B:[3,4,5],
		C:[0.5,0.8,1.2]
	}

	for(let key in price){
		console.log(key,price[key])
	}

//后面继续讲for of
  • es5中将伪数组转换成数组该怎么办

伪数组具备数组的一些特性,具备长度都能遍历,不能直接调用数组方法

  • es6中如何做
<script type="text/javascript">
	//转换 es5中是这样用的 但是不去执行这段代码
	//吧arguments转换成数组
	let args=[].slice.call(arguments) //collection
	let imgs=[].slice.call(document.quarySelectorAll('img')) //NodeList
	console.log(args)

	//es6做法 Array.prototype.from 伪数组转换成数组
	let args = Array.from(arguments)
	let imgs = Array.from(document.quarySelectorAll('img'))
	imgs.forEach()

	let array = Array(5)
	for( let i=0,len=array.length;i<len;i++){ //使用forEach不行
		array[i]=1
	}
	console.log(array)

	//Array.from(arrayLike,mapFn,thisArg)
	//伪数组:按照索引方式存储数据的 具备一个length属性{0:'a',1:'b',length:2}
	let array = Array.from({length:5},function(){return 1})
	console.log(array)
</script>
  • es5中如何创建一个新数组
  • es6中应该如何做
//生成新数组 push pop
	let array = Array(5)
	let array = ['','']

	//Array.prototype.of 
	let array = Array.of(1,2,3,4,5)
	console.log(array)

	//Array.prototype.fill
	let array = Array(5).fill(1)
	console.log(array)

	//Array.fill(value,start,end)
	let array = [1,2,3,4,5]
	console.log(array.fill(8,2,4))
  • es5中如何查找一个元素
  • es6中如何做
//es5查找
	 let array = [1,2,3,4,5]
	// 判断有无(空或非空) 关注的是满足条件的所有元素 返回成数组
	 let find = array.filter(function (item){
	 	return item ===1
	 		return item %2 ===0 ==>2 4
	 })
	 console.log(find)

	// es6 Array.prototype.find 关注的是满足条件的第一个值
	let find= array.find(function(item){
	 	return item %2 ===0 //=>2
	 })
	console.log(find)

	//Array.prototype.findIndex 返回的是索引
	let find= array.findIndex(function(item){
	 	return item %2 ===0 //=1
	 })
	console.log(find)

javascript有哪些元素是可遍历的
如何给数据结构自定义遍历
find()和es5的filter()有什么区别

Class

  • es5中如何声明一个类
  • es6中如何做的
es5中声明类
<script type="text/javascript">
	let Animal = function(type){
		this.type=type;
		// this.eat = function(){
		// 	console.log('eat food')
		// }
	}
	//将方法挂在原型链上
	//将共有的属性方法放到原型链上去
	Animal.prototype.eat = function(){
		console.log('eat food  food')
	}

	let dog = new Animal('dog')
	let cat = new Animal('cat')

	// cat.eat = function(){
	// 	console.log('error')
	// }

	cat.constructor.prototype.eat = function(){
		console.log('error')
	}

	console.log(dog)
	console.log(cat)

	dog.eat()
	cat.eat()
</script>
es6中声明类
class Animal{
		constructor(type){
			this.type=type
		}
		eat(){
			console.log('eat food')
		}
	}

	let dog = new Animal('dog')
	let cat = new Animal('cat')
	console.log(dog)
	console.log(cat)

	dog.eat()
	cat.eat()

get&set属性操作

es6读写属性
let _age=4
class Animal{
		constructor(type){
			this.type=type
		}
		get age(){ //属性 
			return _age;
		}

		set age(value){
			if(value<7&&value>4){
				_age=value
			}
		}
		eat(){
			console.log('eat food')
		}
	}

let dog = new Animal('dog')
console.log(dog.age)
dog.age =5 
console.log(dog.age)

方法

  • es5中如何操作一个方法
  • es6中如何操作
  • 对象实例方法 类的静态方法
es5中操作方法
let Animal = function(type){
		this.type=type;
		//this.eat= function(){}
	}
	
	//实例对象方法
	Animal.prototype.eat = function(){
		Animal.walk()
		console.log('eat food  food')
	}

	//类的静态方法 不能用实例(this)调用
	Animal.walk= function(){
		console.log('i am walking')
	}

	let dog = new Animal()
	dog.eat()
es6操作方法
class Animal{
		constructor(type){
			this.type = type
		}

		eat(){
			Animal.walk()
			console.log('eat food')
		}

		static walk(){
			console.log('i am walking')
		}
	}

	let dog = new Animal()
	dog.eat()

继承

  • es5中怎么继承一个类
  • es6中怎么做
es5中继承一个类
let Animal = function(type){
		this.type=type;
		//this.eat= function(){}
	}
	
	//实例对象方法
	Animal.prototype.eat = function(){
		Animal.walk()
		console.log('eat food  food')
	}

	//类的静态方法 不能用实例(this)调用
	Animal.walk= function(){
		console.log('i am walking')
	}

	let Dog = function (){ 
		//用call改变this的指针 指向dog的实例 实现了一部分父类继承
		//在dog的构造函数中要执行Animal构造函数  初始化父类的构造函数
		Animal.call(this,'dog') 

	}
	//值类型 引用类型
	//关联Dog和Animal的原型链
	Dog.prototype = Animal.prototype

	let dog = new Dog()
	dog.eat()
es6中类的继承
class Animal{
		constructor(type){
			this.type = type
		}

		eat(){
			Animal.walk()
			console.log('eat food')
		}

		static walk(){
			console.log('i am walking')
		}
	}

	class Dog extends Animal{
		constructor(type){
			super(type)
			this.age = 2
		}

	}

	let dog = new Dog()
	dog.eat()
	console.log(dog.age)

Function Updates

  • es5中怎么处理函数参数的默认值
  • es6中怎么做
es5中操作
function f(x,y,z){
		 if(y ===undefined){
		 	y=7
		 }
		 if(z ===undefined){
		 	z=42
		 }

		 return x+y+z
	}
	console.log(f(1))
//es6中
	function f(x,y=7,z=x+y){
		//console.log(arguments.length) 输出传入参数的个数
		//es6中不使用arguments 
		//console.log(Array.from(arguments)) //这里arguments是伪数组

		console.log(f.length) //能获取到没有默认值的参数个数 方法定义的参数 而不是执行时给的参数
		return x+y+z
	}

	console.log(f(1)) //16
	console.log(f(1,undefined,43)) //51
  • es5中怎么处理不确定参数的问题
  • es6中如何去做
es5中的操作
function sum(){
		let num=0
		// Array.prototype.forEach.call(arguments,function(item){
		// 	num = num+item
		// })
			
		Array.from(arguments).forEach(function(item){
			num = num+item
		})

		return num
	}

	console.log(sum(1,2,3))
es6中的操作
function sum(base,...nums){ //所有的(函数传参的)参数都放在nums中 Rest parameter
		//加上base,则是把第一个参数放入base中,其余的参数放入nums中
		let num = 0
		nums.forEach(function(item){ //nums是个数组类型
			num = num+item
		})

		return base*2 + num
	}
	console.log(sum(1,2,3,4))

参数个数确定

//计算三角形周长
	function sum(x=1,y=2,z=3){
		return x+y+z
	}

	let data = [4,5,6]
	console.log(sum(data[0],data[1],data[2]))
	//es5中操作
	console.log(sum.apply(this,data))
	//es6中操作 spread操作
	console.log(sum(...data))
  • es6中的箭头函数是什么
  • ()=>{}
//箭头函数
	let hello = (name,city) => { //有参数且只有一个参数时,()可以省略
		console.log('hello',name,city)
	}
	hello('world','beijing')
let sum = (x,y,z) => x + y + z //箭头后面是表达式 可以省略花括号和return
	

	let sum = (x,y,z) =>({ //以对象形式返回,加个(),{}是对象的花括号
		x: x,
		y: y,
		z: z
	})

	let sum = (x,y,z) => {
		return{
			x: x,
			y: y,
			z: z
		}
	}
let test = {
 name: 'test',
 say: function(){
 console.log(this.name)
}
}
test.say() //谁调用function this就指向谁
let test = {
		name: 'test',
		say: () => {
			console.log(this.name,this) //定义的时候this指向是什么 执行的时候还是什么
			//放到浏览器中执行 this指向window
		}
	}

练习

如何用箭头函数来实现一个数组排序的问题
箭头函数对this的处理还有什么妙用

  • 对象
    • es5中Object属性能简写吗
    • es6中如何处理的
//es5
	let x =1
	let y=2
	let z = 3
	let obj = {
		x,
		y,
    hello: function(){
      console.log('hello') 常规函数 es5中不允许在Object对象中写异步函数
    }
	}
	obj[z] = 5
	console.log(obj)
//es6
	let x =1
	let y=2
	let z = 3
	let obj = {
		x,
		y,
		[z]:6,
		[z+y]:8,
		* hello(){ //异步函数
      console.log('hello')
    	}
	}
	
	// function* functionName() {
		
	// }

	console.log(obj)
	obj.hello()
  • es6中除了用Object存储数据
  • Set 所存储的数据必须是唯一的 不允许重复 重复的数据会自动过滤
  • Set里面的元素是任意值
//Set
	let s = new Set()
	let s = new Set([1,2,3,4]) //Set可接受的对象是可遍历的 不仅仅是数组
	s.add('hello')
	s.add('world')
	s.add('hello').add('world').add('hello')
	console.log(s)

	//删除指定数据
	s.delete('hello')
	console.log(s)
	//全部清空
	s.clear()
	console.log(s)

	//查找 true/false
	console.log(s.has('world'),s.size)

	//读数据
	console.log(s.keys(),s.values())
	//键值对
	console.log(s.entries())

	s.forEach(item => {
		console.log(item)
	})

	for(let item of s){
		console.log(item)
	}

	//改数据 先删在增加
  • es6中Map是什么,解决什么问题,怎么使用
  • Map的key为任意值
let map = new Map([[1,2],[3,4]]) //可以传入可遍历对象 与Set的区别在于 key为任意值

	//添加数据
	map.set(5,6)

	//修改数据
	map.set(1,3)

	//删除数据
	//map.delete(1)
	//map.clear()
	console.log(map)


	//统计数据
	console.log(map.size)
	
	//查找数据
	console.log(map.has(3))

	//取数据
	console.log(map.get(1))
	
	console.log(map.keys(),map.values(),map.entries())

	// map.forEach(function(item){
	// 	console.log(item)
	// })

	map.forEach((value,key) => { //value key
		console.log(value,key)
	})

	for(let [key,value] of map){ //key value
		console.log(key,value)
	}

	let o = function(){
		console.log('o')
	}

	map.set(o,4)
	console.log(map)

	//map性能比Object稍微有点优势

在这里插入图片描述
在这里插入图片描述

  • es5中怎么把一个对象复制到另一个对象上
  • es6如何做
//es6中
	const target = {}
	const source = {b:4,c:5}
	Object.assign(target,source)
	console.log(target)
const target = {
		a:{
			b:{
				c:{
					d:3
				}
			},
			e: 1,
			f: 2,
			h: 4   //拷贝过去h没有了 因为assign是浅复制
		}
	}
	const source = {
		a:{ 
			b:{
				c:{
					d:1
				}
			},
			e: 5,
			f: 6
		}
	}
	Object.assign(target,source) //浅复制 对于不是引用类型的值 做数据的替换
	//对于引用类型的值 不再遍历 把引用的地址换一下
	//递归 assign处理 实现深拷贝
	console.log(target)

练习
如果目标对象传入的是undefined和null将会怎样
如果源对象的参数是undefined和null将会怎样
如果目标对象是个嵌套的对象 ,子对象的属性会被覆盖吗

  • weakSet weakMap

  • 不常用 基本与Set Map相同 api也相同

  • weakSet存储的数据只能是对象

  • weakMap只允许接收对象类型的key

  • RegExp

    • es6中的y修饰符是什么含义
    • es5支持y修饰符吗
const s = 'aaa_aa_a'
	const r1 = /a+/g  //全局语法任意位置匹配
	const r2 = /a+/y //sticky 粘连 就是要从剩余的_aa_a中匹配,因为是下划线所以匹配为空 匹配要连续

	console.log(r1.exec(s)) //aaa
	console.log(r2.exec(s)) //aaa

	console.log(r1.exec(s)) //aa
	console.log(r2.exec(s)) //null 
  • es5如何在正则中处理中文问题 如果是多个字节
  • es6中如何处理
//unicode u修饰符
	let s = '𠮷'
	let s2 = '\uD842\uDFB7'

	console.log(/^\uD842/.test(s2))
	console.log(/^\uD842/u.test(s2)) //遇到中文字符的时候加u

	console.log(/^.$/.test(s)) //.匹配任意字符
	console.log(/^.$/u.test(s)) 

	//unicode码点怎么在正则中使用 u+20BB7
	console.log(/\u{20BB7}/u.test(s))
	console.log(/\u{61}/u.test('a'))

	console.log(/𠮷{2}/u.test('𠮷𠮷'))

	console.log(/[a-z]/i.test('\u212A'))
	console.log(/[a-z]/iu.test('\u212A'))

http://www.fileformat.info/info/unicode/char/20bb7/index.htm

阅读
unicode及编码方式概述
unicode转utf-16的转码公式
sticky
练习
sticky模式有什么实际应用场景
上面提到的\uD842\uDFB7 是四个字节 加上u标识符会正确的识别出是两个字符,在javascript里一个字符是多少字节
U+20BB7是如何计算出\uD842\uDFB7

  • Template
    • es5中字符串换行,包含变量或表达式,包含逻辑运算怎么办
    • es6怎么做的
const a = 20
	const b =10
	const c = 'javascript'
	//es5
	const str = 'my age is' + (a+b) + 'i love' + c
	//es6
	const str = `my age is ${a+b} i love ${c}`
	console.log(str)

//es5
	const retailPrice = 20
	const wholeSalePrice = 16
	const type = 'retail'
	let showTxt = ''
	if(type === 'retail'){
		showTxt = '您此次的购买单价是:'+ retailPrice
	}else{
		showTxt = '您此次的购买批发价是:'+wholeSalePrice
	}
	console.log(showTxt)

//es6
	function Price(strings,type){
	let s1 = strings[0]
	const retailPrice = 20
	const wholeSalePrice = 16
	let showTxt = ''
	if(type === 'retail'){
		showTxt = '购买单价是:'+ retailPrice
	}else{
		showTxt = '购买批发价是:'+wholeSalePrice
		}
		return `${s1}${showTxt}`
	}

	let showTxt =Price`您此次的${'retail'}`
	console.log(showTxt)
//es5
	let s1 ='第一行'+
	'第二行'

	//es6
	let s1 = `第一行
	我是第二行`
	console.log(s1)

练习
用Tag函数解决业务中的一个字符串模板问题

  • destructure
    • es5从一个复杂的数据结构中提取数据是如何做的
    • es6如何去做
    • 解构赋值
let arr = ['hello','world']
	let firstName = arr[0]
	let surName = arr[1]
	console.log(firstName,surName)

	let arr = ['hello','world']
	let [firstName,surName] = arr
	console.log(firstName,surName)
let arr = ['a','b','c','d']
	let[firstName,,thirdName] = arr
	console.log(firstName,thirdName)

	let arr = 'abcd'  
	let[firstName,,thirdName] = new Set([1,2,3,4]) //一般支持可遍历的
	console.log(firstName,thirdName)
let user = {name:'s',surName:'t'};
	[user.name,user.surName] = [1,2]
	console.log(user)
//循环
	let arr = ['hello','world']
	for(let i =0;i<arr.length;i++){
		item = arr[i]
		console.log(item)
	}
	

	let user ={name: 's',surName:'t'}
	for(let [k,v] of Object.entries(user)){
		console.log(k,v)
	}
let arr =[1,2,3,4,5,6,7,8,9]
	let [firstName,curName, ...last] = arr
	console.log(firstName,curName,last)

	let arr =[]
	let [firstName = 'hello',curName, ...last] = arr
	console.log(firstName,curName,last)
  • 对象的解构赋值
//Object
	let options = {
		title: 'menu',
		width: 100,
		height: 200
	}

	let{title:title2,width,height} = options
	console.log(title2,width,height)

	let options = {
		title: 'menu',
		width: 100,
		height: 200
	}

	let{title,...last} = options
	console.log(title,last)
let options = {
		size:{
		width: 100,
		height: 200
	},
	items: ['cake','donut'],
	extras: true
		
	}

	let { size:{width: width2, height}, items: [item1] ,extras} = options
	console.log(width2,height,item1,extras)

练习
一个函数需要传入很多参数,是否可以利用解构赋值来简化操作
如何在业务开发中对接口数据进行解构赋值

  • Promise
    • es5中的回调地狱 a回调b b回调c c回调d
    • es6是如何通过异步操作来实现的
//es5中的异步加载js
	function loadScript (src) {
		let script = document.createElement('script') //向页面动态创建一个dom节点
		script.src = src
		document.head.append(script)
	}

	function test(){ //等1.js加载完成之后再让test执行
		console.log('test')
	}

	loadScript('1.js') //js单线程 加载js后,异步操作放到异步队列中执行,会立马执行test()
	test()


————————————————————————————————————————————————————————————
加载一个js文件
function loadScript (src,callback) {
		let script = document.createElement('script') 
		script.src = src
		//script.οnlοad=function (){callback()}
		script.onload = ()=>{
			callback()
		}
		document.head.append(script)

	}

	function test(){ 
		console.log('test')
	}

	loadScript('1.js',test) 
——————————————————————————————————————————————————————————————
es5中加载多个js文件
function loadScript (src,callback) {
		let script = document.createElement('script') 
		script.src = src
		//script.οnlοad=function (){callback()}
		script.onload = ()=>{
			callback()
		}
		document.head.append(script)

	}

	function test(){ 
		console.log('test')
	}

	loadScript('1.js',function(script){
		loadScript('2.js',function(script){
			loadScript('3.js',function(script){
				
			})
		})
	}) 
function loadScript(src){
		//pending undefined
		return new Promise((resolve,reject)=> {
			let script = document.createElement('script')
			script.src = src
			script.onload = () => resolve(src) //fullfilled result
			script.onerror = () => reject(err) //rejected error
			document.head.append(script)
		})
	}

	loadScript('1.js').then(loadScript('2.js')).then(loadScript('3.js'))

//promise.then(onFullfilled,onRejected)
  • then的语法

    • .then是promise对象原型上方法,只要是promise对象就可以调用.then方法
    • 支持的语法then(onFullfilled,onRejected)对应着 resolve()与reject()
    • (onFullfilled,onRejected)两个参数都为函数类型(第一个必选,第二个可选)
    • 这里loadScript(‘2.js’)不是方法 而是方法的返回值
    • 如果onFullfilled,onRejected这两个参数被遗漏或着不是函数 则忽略掉这两个内容
    • loadScript(‘2.js’)表达式会被计算 所以执行了
  • 为什么then可以链式调用

    • then是返回一个新的promise实例
    • 没有onFullfilled,onRejected这两个参数时(非函数),返回一个新的空promise对象

1.js 2.js 3.js执行的过程

loadScript('1.js')
	.then(() =>{
	 return	loadScript('4.js') 返回一个promise对象
  //注意加return与不加return时的情况区别
	},(err) => {
		console.log(err)
	})
	.then(()=>{
		loadScript('3.js')
	},(err)=>{
		console.log(err)
	})
  • 把一个数字转换成promise对象
    • 使用Promise.resolve()与Promise.reject()静态方法
function test(bool){
		if(bool){
			return new Promise((resolve,reject)=>{
				resolve(30)
			})
		}else{
			return Promise.resolve(42) //可以将非异步操作转换成异步操作
		}
	}

	test(1).then((value) =>{
		console.log(value)
	})
function test(bool){
		if(bool){
			return new Promise((resolve,reject)=>{
				resolve(30)
			})
		}else{
			return Promise.reject(new Error('ss')) //可以将非异步操作转换成异步操作
		}
	}

	test(0).then((value) =>{
		console.log(value)
	},(err)=>{
		console.log(err)
	})
  • promise对异常的处理
    • catch是promise对象原型链上的方法
    • 捕获链式操作上reject抛出的异常
function loadScript(src){
		//pending undefined
		return new Promise((resolve,reject)=> {
			let script = document.createElement('script')
			script.src = src
			script.onload = () => resolve(src) //fulfilled result
			script.onerror = (err) => reject(err) //rejected error
			document.head.append(script)
		})
	}

	
	loadScript('1.js')
	.then(() =>{
	 return	loadScript('4.js') //返回一个promise对象
	})
	.then(()=>{
	  return loadScript('3.js')
	})
	.catch((err) =>{ //catch是promise对象原型链上的方法 捕获链式操作上reject抛出的异常
		console.log(err)
	})
  • promise并行异步操作
//模拟三个并发场景
	const p1 = Promise.resolve(1)
	const p2 = Promise.resolve(2)
	const p3 = Promise.resolve(3) //不用关心哪个数据先返回
	Promise.all([p1,p2,p3]).then((value) =>{ //Promise.all返回的还是一个Promise对象
		console.log(value)
	})
  • promise 竞争 线路1 线路2 先到先得
//竞争 先到先得 1线路 2线路

	const p1 = () =>{
		return new Promise((resolve,reject) =>{
			setTimeout(function(){
				resolve(1)
			},1000)
		})
	}

	const p2 = () =>{
		return new Promise((resolve,reject) =>{
			setTimeout(function(){
				resolve(2)
			},0)
		})
	}

	Promise.race([p1(),p2()]).then((value)=>{
		console.log(value)
	})

练习
按顺序加载脚本的代码不太直观看出顺序执行的过程,如果按顺序延时执行是不是更好理解
请用Promise实现一个接口

  • reflect 反射
    • 什么是反射机制
    • java的反射机制是在编译阶段不知道哪个类被加载,而是在运行的时候才加载,执行
console.log(Math.floor.apply(null,[3.72]))

console.log(Reflect.apply(Math.floor,null,[3.72]))
let price =91.5
	if(price >100){
		console.log(Math.floor.apply(null,[price]))
	}else{
		console.log(Math.ceil.apply(null,[price]))
	}

	console.log(Reflect.apply(price>100 ? Math.floor : Math.ceil,null,[price]))
 let d = new Date()
console.log(d.getTime)

let d = Reflect.construct(Date,[]) //调用不同的类 去动态实例化对象
console.log(d.getTime(),d instanceof Date)
const student = {}

	const r1 =Object.defineProperty(student,'name',{value:'mike1'})
	console.log(student,r1)

	const r2 =Reflect.defineProperty(student,'name',{value:'mike2'})
	console.log(student,r2)
const obj = {x:1,y:2}
	Reflect.deleteProperty(obj,'x')
	console.log(obj)

	console.log(Reflect.get(obj,'y'))
	console.log(Reflect.get([3,4],1))
//获取对象下的属性的标识符
	const obj = {x:1,y:2}
	console.log(Reflect.getOwnPropertyDescriptor(obj,'y'))
	console.log(Object.getOwnPropertyDescriptor(obj,'x'))

	//获取某个对象的原型对象是什么
	let d = new Date()
	console.log(Reflect.getPrototypeOf(d))

	//判断对象上有无该属性
	const obj1 = {x:1,y:2}
	console.log(Reflect.has(obj1,'x'))  //has方法Object没有

	//判断对象是否可扩展
	Object.freeze(obj)  //冻结obj 使其不可扩展 不能新增属性了

	console.log(Reflect.isExtensible(obj))

	//判断某个对象下的自由属性 自身属性 不是原型链的属性
	console.log(Reflect.ownKeys(obj))
	console.log(Reflect.ownKeys([1,2]))

	//Reflect提供的禁止扩展的api
	Reflect.preventExtensions(obj)
	console.log(Reflect.isExtensible(obj))


	// Reflect set
	const obj2 = {x:1,y:2}
	Reflect.set(obj2,'z',4)
	console.log(obj2)

	const arr = ['duck','duck','duck']
	Reflect.set(arr,2,'goose')
	console.log(arr)

	//修改实例对象的原型对象
	const arr1 = ['duck','duck','duck']
	console.log(Reflect.getPrototypeOf(arr))
	Reflect.setPrototypeOf(arr,String.prototype)
	console.log(Reflect.getPrototypeOf(arr))
  • Proxy
    • 代理功能
    • 中介场景
let o = {
		name :'xiaoming',
		price: 190
	}

	let d = new Proxy(o,{  //代理相当于中介 中间商赚差价
		get(target,key){ //target就是我们代理的对象
			if(key === 'price'){
				return target[key]+20
			}else{
				return target[key]
			}
		}
	}) //第一个参数你要代理谁 第二个参数代理后能做什么

	console.log(d.price,d.name)
//后端数据排序后 进行还原 (只读不可写)
	let o = {
		name :'xiaoming',
		price: 190
	}

	let d = new Proxy(o,{ 
		get(target,key){ 
			return target[key]
		},

		set(target,key,value){
			return false; //不让你赋值
		}
	}) 

	d.price =300  //没起作用 拦截了赋值操作 暴露的是d 而不去暴露o
	console.log(d.price,d.name)
es5中的操作方法
let o = {
		name :'xiaoming',
		price: 190
	}
	for(let [key] of Object.entries(o)){
		Object.defineProperty(o,key,{
			writable:false
		})
	}
	o.price =300 //不起作用
	console.log(o.name,o.price)
//有不合理的操作,如何保护我们的数据 校验
//数据结构不会被破坏 写数据时校验规则
	let o = {
		name :'xiaoming',
		price: 190
	}

	let d = new Proxy(o,{
		get(target,key){
			return target[key] || ''
		},
		set(target,key,value){
			if(Reflect.has(target,key)){
				if(key ==='price'){
					if(value >300){
						return false
					}else{
						target[key] =value
					}
				}else{
					target[key] =value
				}

			}else{
				return false;
			}
		}
	})

	d.price = 400
	d.name = 'chen'
	d.age = 400
	console.log(d.price,d.name,d.age)
//解耦
let o = {
		name :'xiaoming',
		price: 190
	}

	let validator = (target,key,value) =>{
		if(Reflect.has(target,key)){
				if(key ==='price'){
					if(value >300){
						return false
					}else{
						target[key] =value
					}
				}else{
					target[key] =value
				}

			}else{
				return false;
			}
	}

	let d = new Proxy(o,{
		get(target,key){
			return target[key] || ''
		},
		set: validator
	})

	d.price = 400
	d.name = 'chen'
	d.age = 400
	console.log(d.price,d.name,d.age)
//监听错误
	window.addEventListener('error',(e) =>{
		console.log(e.message)

		// report('/') 上报逻辑
	},true)

	//提升用户体验  监控违规操作 触发报错
	let o = {
		name :'xiaoming',
		price: 190
	}

	//校验规则
	let validator = (target,key,value) =>{
		if(Reflect.has(target,key)){
				if(key ==='price'){
					if(value >300){
						//不满足规则就要触发错误
						throw new TypeError('price 超过了 300')
					}else{
						target[key] =value
					}
				}else{
					target[key] =value
				}

			}else{
				return false;
			}
	}

	let d = new Proxy(o,{
		get(target,key){
			return target[key] || ''
		},
		set: validator
	})

	d.price = 400
	d.name = 'chen'
	d.age = 400
	console.log(d.price,d.name,d.age)
//给主键随机生成id 只读且唯一
	class Component{
		// constructor(){
		// 	this.id = Math.random().toString(36).slice(-8)
		// } 不行
		// get id() {
		// 	return Math.random().toString(36).slice(-8)
		// } 不行

		constructor(){
			this.proxy = new Proxy({
				id:Math.random().toString(36).slice(-8)
				},{})
		}

		get id(){
			return this.proxy.id
		}
	}

	let com1 = new Component()
	let com2 = new Component()
	for(let i =0; i<10;i++){
		console.log(com1.id,com2.id)
	}
	com1.id = 'abc'
	console.log(com1.id,com2.id)
  • 在代理使用过程中 如何撤销代理
//如何撤销代理
	let o = {
		name :'xiaoming',
		price: 190
	}

	let d = Proxy.revocable(o,{   //现在d包含代理的数据 以及撤销的操作 不仅仅是数据了
		get(target,key){ 
			if(key === 'price'){
				return target[key]+20
			}else{
				return target[key]
			}
		}
	})

	console.log(d.proxy.price,d)
	setTimeout(function(){
		d.revoke()
		setTimeout(function(){
			console.log(d.proxy.price)
		},100)
	},1000)

练习
组件初始化的时候都赋值一个可读且随机的id 该怎么做
临时代理有哪些应用场景
如何把接口的数据用代理进行包装

  • Generator
    • es6如何让遍历停下来
//es5循环
	// function loop(){
	// 	for(let i =0; i<5;i++){
	// 		console.log(i)
	// 	}
	// }

	// loop()

	//es6
	function * loop(){
		for(let i =0; i<5;i++){
			yield console.log(i) //使用yield暂停函数的运行
		}
	}

	const l = loop()
	l.next()
	l.next()
function * gen(){
		let val
		val = yield 1
		console.log(val)
	}

	const l = gen()
	l.next() //next找yield或者函数结尾 就会暂停或者结束
	l.next()
function * gen(){ //generator是一个函数 比普通函数多了*
		let val
		val = yield * [1,2,3] //加*表示后面是个可遍历的对象
		console.log(val)
	}

	const l = gen()
	console.log(l.next()) //会返回当前执行的状态与结果
	console.log(l.next())
function * gen(){ 
		let val
		val = yield [1,2,3] 
		console.log(val)
	}

	const l = gen()
	console.log(l.next(10)) 
	console.log(l.next(20))
function * gen(){ 
		let val
		val = (yield [1,2,3])+7
		console.log(val)
	}

	const l = gen()
	console.log(l.next(10))
	console.log(l.return(100))
	console.log(l.next(20))
//es5 抽奖
	function drow(first=1,second = 2,third = 3){
		let firstPrice = ['1A','1B','1C','1D','1E'];
		let secondPrice = ['2A','2B','2C','2D','2E','2F','2G'];
		let thirdPrice = ['3A','3B','3C','3D','3F','3G','3H','3I','3Q','3S'];
		let result =[]
		let random
		//抽一等奖
		for (let i = 0; i < first; i++) {
			random = Math.floor(Math.random()*firstPrice.length)
			console.log(Math.random()*firstPrice.length,random)
			result = result.concat(firstPrice.splice(random,1))
		}
		for (let i = 0; i < second; i++) {
			random = Math.floor(Math.random()*secondPrice.length)
			result = result.concat(secondPrice.splice(random,1))
		}
		for (let i = 0; i < third; i++) {
			random = Math.floor(Math.random()*thirdPrice.length)
			result = result.concat(thirdPrice.splice(random,1))
		}

		return result
	}

	let d = new drow()
	for(let value of d){
		console.log(value)
	}
//es6
	function * drow(first=1,second = 2,third = 3){
		let firstPrice = ['1A','1B','1C','1D','1E'];
		let secondPrice = ['2A','2B','2C','2D','2E','2F','2G'];
		let thirdPrice = ['3A','3B','3C','3D','3F','3G','3H','3I','3Q','3S'];
		let count = 0
		let random
		
		while(1){
			if(count<first){
				random = Math.floor(Math.random()*firstPrice.length)
				yield firstPrice[random]
				count++
				firstPrice.splice(random,1)
			}else if(count<first+second){
				random = Math.floor(Math.random()*secondPrice.length)
				yield secondPrice[random]
				count++
				secondPrice.splice(random,1)
			}else if(count<first+second+third){
				random = Math.floor(Math.random()*thirdPrice.length)
				yield thirdPrice[random]
				count++
				thirdPrice.splice(random,1)
			}else{
				return false
			}
		}
	}

	let d =  drow()
	console.log(d.next().value)
	console.log(d.next().value)
	console.log(d.next().value)
	console.log(d.next().value)
	console.log(d.next().value)
	console.log(d.next().value)
//数到3的倍数就加1
	function * count(x = 1){
		while(1){
			if(x%3===0){
				yield x
			}
			x++
		}
	}

	let c = count()
	console.log(c.next().value)
	console.log(c.next().value)
	console.log(c.next().value)

练习
用generator实现一个斐波那契数列
用generator给自定义数据结构写一个遍历器

  • Iterator
    • 如何让不支持遍历的数据结构"可遍历"
es5遍历方法
let authors ={
		allAuthors: {
			a:['克莱尔','东野圭吾','lp'],
			b:['neal','arthru','ribert'],
			c:['j.r.tole','j.m.r','terry p.k']
		},
		address:[]
	}

	let r =[]
	for(let [,v] of Object.entries(authors.allAuthors)){
		r = r.concat(v)
	}
	console.log(r)
es6遍历实现
let authors ={
		allAuthors: {
			a:['克莱尔','东野圭吾','lp'],
			b:['neal','arthru','ribert'],
			c:['j.r.tole','j.m.r','terry p.k']
		},
		address:[]
	}

authors[Symbol.iterator] = function (){
		let allAuthors = this.allAuthors
		let keys = Reflect.ownKeys(allAuthors)
		let values = []
		return {
			next(){
				if(!values.length){
					if(keys.length){
						values = allAuthors[keys[0]]
						keys.shift()
					}
				}

				return{
					done:!values.length,
					value:values.shift()
				}
				
			}
		}
	}

	let r =[]
	for(let v of authors){
		r.push(v)
	}
	console.log(r)
使用generator改造遍历
authors[Symbol.iterator] = function * (){
		let allAuthors = this.allAuthors
		let keys = Reflect.ownKeys(allAuthors)
		let values = []
		while(1){
			if(!values.length){
				if(keys.length){
					values = allAuthors[keys[0]]
					keys.shift()
					yield values.shift()
				}else{
					return false
				}
			}else{
				yield values.shift()
			}
		}
	}

练习
什么是自定义遍历 如果有复杂的数据结构会使用自定义遍历吗
什么是迭代协议 可迭代协议
generator和iterator的关联关系理解了吗

  • Module
    • es6如何把代码进行模块化设计
基本的导入导出
// export const name ='hello'
// export let addr = 'beijing'
// export var list = [1,2,3]

const name ='hello'
let addr = 'beijing'
var list = [1,2,3]

export default name  //默认导出只有一个
export {
	addr,
	list 
}
_______________________________________________________________
import name,{addr as addr2,list} from 'lesson2-19-mod'

	console.log(name,addr2,list)
  • 导入导出函数
export function say(content){
	console.log(content)
}

export function run(){
	console.log('running')
}

import {say,run} from 'lesson2-19-mod'
	say('hello world')
	run()
  • 导出一个对象
export default {
	code: 1,
	message: 'success'
}

import obj from 'lesson2-19-mod'
	console.log(obj)
  • 导入导出多个对象
const data = {
	code:1,
	message: 'success'
}

const des = {
	age : 20,
	addr: 'beijing'
}

export default {
	data,
	des
}

import obj from 'lesson2-19-mod'
	let {data,des} = obj
	console.log(data,des)
  • 类的导入导出
class Test{
	constructor(){
		this.id = 2
	}
}

// export default Test
export{
	Test
}

import {Test} from 'lesson2-19-mod'
	let test = new Test()
	console.log(test.id)

___________________________________
默认导入导出
export default class{
	constructor(){
		this.id = 2
	}
}

import Test from 'lesson2-19-mod'
	let test = new Test()
	console.log(test.id)
  • 导入导出多个类
export  class Test{
	constructor(){
		this.id = 2
	}
}

export  class Animal{
	constructor(){
		this.name = 'dog'
	}
}

export default class People{
	constructor(){
		this.id = '132'
	}
}

import * as mod from 'lesson2-19-mod'
	let test = new mod.Test()
	console.log(test.id)

	let animal = new mod.Animal()
	console.log(animal.name)

	let people = new mod.default()
	console.log(people.id)

被导出的模块是否能在本模块使用

export function say(){
	console.log('hello')
}

export function run(){
	say()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值