ES6(下)

171 阅读3分钟

迭代器Iterator

一种新的遍历机制,两个核心

1.迭代器是一个接口,能快捷的访问数据,通过 Symbol.iterator来创建迭代器,通过next()获取迭代之后的结果。

2.迭代器是用于遍历数据结构的指针(数据库的游标)

<script type="text/javascript">
	//使用迭代
	const items =  ['one','two',"three"];
	//创建新的迭代器
	const ite = items[Symbol.iterator]()
	console.log(ite.next());//{value: "one", done: false},done表示是否遍历完成,false表示遍历继续
	console.log(ite.next());//{value:"two",done:false}
	console.log(ite.next());//{value:"three",done:false}
	console.log(ite.next());//{value:undefined,done:true}
</script>

生成器Generator

Generator函数,可以通过 yield 关键字,将函数挂起(让函数停留在当前位置),为改变执行流提供了可能性,同时为异步编程也提供了方案。

与普通函数的区别

  1. function 后面,函数名之前有个 *
  2. 只能在函数内部使用yield表达式,让函数挂起

不理解的话,参考www.w3cschool.cn/escript6/es…

<script type="text/javascript">
	function* fn(){
	    yield 2;
	    yield 3;
	    yield 4;
	}
	let a =fn();//返回一个遍历器对象,可以调用next()
    //理解:当函数调用时,返回了一个遍历器对象,函数并不执行
	console.log(a.next());//{value:2,done:false}
	console.log(a.next());//{value:3,done:false}
	console.log(a.next());//{value:4,done:false}
        console.log(a.next());//{value:undefined,done:true}
	//总结
	//generator函数是分段执行的,yield语句暂停执行,而next()恢复执行 
</script>

next方法的参数

yield表达式本身没有返回值,或者说总是返回 undefined 。 next 方法可以带一个参数,该参数就会被当作上一个 yield 表达式的返回值。

function* add(){
	console.log('start');
	let x = yield "2";
	console.log('one:'+x);
	let y = yield '3';
	console.log('two:'+y);
	return x+y;
}
let f = add();
console.log(f.next());//start {value: "2", done: false}
console.log(f.next(10));//one:10 {value: "3", done: false}
console.log(f.next(20));//two:20 {value: 30, done: true}
console.log(f.next());// {value: undefined, done: true}

使用场景

为不具备 Iterator接口的对象提供了遍历操作

<script type="text/javascript">
    		//自定义生成器
			function* objectEntries(obj){
				// 获取对象所有的key保存到数组中[name,age]
				const propsKeys = Object.keys(obj);
				for (const propKey of propsKeys){
					yield [propKey,obj[propKey]];
				}
			}
			const obj = {
				name:'john',
				age:18
			}
            //构造一个生成器
			obj[Symbol.iterator] = objectEntries;
			console.log(obj);
			for (let [key,val] of objectEntries(obj)){
                //for of中做的操作逐次调用next(),返回next().value,拿到value值
				console.log(`${key}:${val}`);
			}
</script>

应用

可以使异步代码同步

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>生成器的应用</title>
	</head>
	<body>
		<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			//Ajax自己去学
			
			//作用:可以部署ajax操作,让异步代码同步化
			//回调地狱
			/* $.ajax({
				url:'https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814',
				method:'get',
				success(res){
					console.log(res);
					//继续发送ajax
					$.ajax({
						url:'',
						method:'get',
						success(res1){
							//发送请求
							$.ajax({
								url:'',
								method:'get',
								success(res2){
								
								}
							})
						}
						
					})
				}
			}) */
			
			//用生成器
			/* function* main(){
				let res = yield request('https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814');
				console.log(res);
				console.log('数据请求完成');
			}
			const ite = main();
			ite.next();
			function request(url){
				$.ajax({
					url,
					method:'get',
					success(result){
						//此处的next()为第二次调用
						ite.next(result);
					}
				})
			} */
			
			
			/* function loadUi(){
				console.log('loading');
			}
			function showData(){
				setTimeout(()=>{
					console.log('数据加载完成');
				},5000)
			}
			function closeUi(){
				console.log('关闭');
			}
			loadUi();
			showData();
			closeUi(); */
			
			function* load(){
				loadUi();
				yield showData();
				closeUi();
			}
			let itLoad = load();
			itLoad.next();
			function loadUi(){
				console.log('loading');
			}
			function showData(){
				//模拟异步操作
				setTimeout(()=>{
					console.log('数据加载完成');
					itLoad.next()
				},5000)
			}
			function closeUi(){
				console.log('关闭');
			}
		</script>
	</body>
</html> 

Promise

相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果。

各种异步操作都可以用同样的方法进行处理。

特点

对象的状态不受外界影响,处理异步操作三个状态

  • pending进行中
  • resolved已完成
  • rejected失败

一旦状态改变,就不会在变,任何时候都可以得到这个结果。

<script type="text/javascript">
		/* let pro = new Promise((resolved,rejected)=>{
			//执行异步操作
			let res = {
				code:201,
				data:{
					name:'john'
				},
				error:'failed'
			};
			setTimeout(()=>{
				if(res.code===200){
					resolved(res.data);
				}else{
					rejected(res.error)
				}
			},1000)
		});
		console.log(pro);//Promise object
		pro.then(val=>{
			console.log(val);
			//val 就是res.data
			
		},(error)=>{
			console.log(error);
			//error 就是res.error
		}) */
		
		
    
    	//传参
		function timeOut(ms){
            //闭包
			return new Promise((resolved,rejected)=>{
				setTimeout(()=>{
					resolved('hello')
				},ms)
			})
		}
		timeOut(2000).then((val)=>{
			console.log(val);
		});
</script>

封装Ajax

<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title></title>
</head>
<body>
	<script type="text/javascript">
		//https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814
	function getJson(url){
		return new Promise((resolved,rejected)=>{
            //发送ajax请求
			const xhr = new XMLHttpRequest();
            //方式必须大写
			xhr.open('GET',url);
			xhr.onreadystatechange = handler;
            //返回类型
			xhr.responseType = 'json';
            //设置请求头
			xhr.setRequestHeader('Accept','application/json');
			//发送,get方法没有请求体
			xhr.send();
			
			function handler(){
				// console.log(this.readyState);
				if (this.readyState === 4){
					if(this.status === 200){
                        //成功
						resolved(this.response.HeWeather6)
					}else{
                        //失败
						rejected(new Error(this.statusText));
					}
				}
			}
		})
	}
	getJson('https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814').then((data)=>{
		console.log(data);
	},(error)=>{
		console.log(error);
	})
	</script>
</body>
</html>

相关方法

then() & catch()

第一个参数是resolve回调函数,第二个参数是可选的,是reject状态回调的函数。then()返回的是一个新的promise实例,可以采用链式编程。

getJson('https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814').then((data)=>{
		console.log(data);
	}).then(null,err=>{
    console.log(err);
})
//这样书写并不友好

//可以有替代写法,用catch
getJson('https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814').then((data)=>{
		console.log(data);
	}).catch(err=>{
    console.log(err);
})

resolve()

能将现有的任何对象转换成promise对象

let p = Promise.resolve('foo');
// 等价于
let p = new Promise(resolve=>resolve('foo'))
console.log(p);
p.then((data)=>{
	console.log(data);
})

reject()

与resolve()方法一样

all()

异步并行

let p1 =new Promise((resolve,reject)=>{})
let p2 =new Promise((resolve,reject)=>{})
let p3 =new Promise((resolve,reject)=>{})
let p4 = Promise.all([p1,p2,p3]);
p4.then(()=>{
	//同则生
}).catch(err=>{
	//异则死
})

race()

给某个异步的请求设置超时的时间,并且在超时后执行相应的操作

<script type="text/javascript">
		//请求图片资源
		function requestImg(imgSrc){
			return new Promise((resolve,reject)=>{
				const img = new Image();
				img.onload = function(){
					resolve(img);
				}
				img.src = imgSrc;
			})
		}
		function timeOut(){
			return new Promise((resolve,reject)=>{
				setTimeout(()=>{
					reject(new Error('图片请求超时'))
				},2000)
			})
		}
		Promise.race([requestImg('1.jpg'),timeOut()]).then(data=>{
			console.log(data);
			document.body.appendChild(data);
		}).catch(err=>{
			console.log(err);
		})
</script>

async

返回一个promise对象,其实是generator的语法糖

作用:使异步操作更加方便

<script type="text/javascript">
		async function f(){
			return await 'hello'
		}
		//如果async函数中有多个await,那么then()会等待所有的await指令 运行完的结果才去执行
		f().then(val=>{
			console.log(val);
		}).catch(e=>{
			console.log(e);
		});
		async function fn(){
			throw new Error('出错了')
		}
		fn().then(v=>{
			console.log(v);
		}).catch(e=>{
			console.log(e);
		})
</script>

封装ajax

<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title></title>
</head>
<body>
	<script type="text/javascript">
		//https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814
	
		function getJson(url){
				return new Promise((resolved,rejected)=>{
					const xhr = new XMLHttpRequest();
					xhr.open('GET',url);
					xhr.onreadystatechange = handler;
					xhr.responseType = 'json';
					xhr.setRequestHeader('Accept','application/json');
					//发送
					xhr.send();
					
					function handler(){
						// console.log(this.readyState);
						if (this.readyState === 4){
							if(this.status === 200){
								resolved(this.response)
							}else{
								rejected(new Error(this.statusText));
							}
						}
					}
				})
			}
	
		async function getNowWeather(url){
			//发送ajax 获取实况天气
			let res = await getJson(url);
			console.log(res);
			// 获取HeWeather6数据,获取未来3-7天的天气状况
			let arr = await res.HeWeather6;
			return arr[0].now;
		}
		getNowWeather('https://free-api.heweather.net/s6/weather/now?location=changchun&key=20abbcefae5c4148b23c674102d0e814')
		.then(data=>{
			console.log(data);
		}).catch(e=>{
			console.log(e)
		})
	</script>
</body>
</html>

class类的用法

类的创建

<script type="text/javascript">
		//es5创建类
		/* function Person(name,age){
			this.name = name;
			this.age = age;
			
		}
		Person.prototype.sayName = function(){
			return this.name;
		}
		let p = new Person('huahua','18');
		console.log(p);
		 */
		//es6
		class Person{
			//实例化时,立即被调用
			constructor(name,age) {
			    this.name = name;
				this.age = age
			}
			/* 
			sayName(){
				return this.name;
			}
			sayAge(){
				return this.age;
			}
            */
		}
		//通过Object.assign()可以添加多个方法
		Object.assign(Person.prototype,{
			sayName(){
				return this.name;
			},
			sayAge(){
				return this.age;
			}
		})
		let p = new Person('huahua',18);
		console.log(p);
</script>

类的继承

<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title></title>
</head>
<body>
	<script type="text/javascript">
		class Animal{
			constructor(name,age) {
				this.name= name;
				this.age = age;
			}
			sayName(){
				return this.name;
			}
			sayAge(){
				return this.age;
			}
		}
		class Dog extends Animal{
			constructor(name,age,color) {
				//继承父类属性
			    super(name,age);
				//等价于
				// Animal.call(this,name,age);
				//子类属性
				this.color = color;
			}
			//子类方法
			sayColor(){
				return `${this.name}:${this.color}`
			}
			//重写父类方法
			sayName(){
                //super相当于Animal.prototype
				return this.name+ super.sayAge()+ this.color;
			}
		}
		let d = new Dog('huahua',3,'red');
		console.log(d);
		console.log(d.sayName());
		console.log(d.sayAge());
		console.log(d.sayColor());
		console.log(d.sayName());
	</script>
</body>
</html>

ES6模块化的实现

es6模块功能主要有两个命令构成:export和import

一个模块就是一个独立的文件

export

用于规定模块的对外接口

index.js文件如下

export const name = 'john';
export const age = 18;
export function sayName(){
	return name
}
//抛出默认值
const obj = {
    foo:'foo'
}
export default obj

import

用于输入其他模块提供的功能

main.js

<script type='module'>
    //此处的obj可以自定义
	import obj,{name,age,sayName} from 'index.js';
    /*导入所有
    import * as f from 'index.js';*/
    console.log(obj);
    console.log(name,age,sayName());
    console.log(f);
    console.log(f.default);
</script>